Skip to content

Commit 730e163

Browse files
author
idekctf
authoredJun 25, 2021
Add files via upload
1 parent 30cd941 commit 730e163

File tree

5 files changed

+429
-0
lines changed

5 files changed

+429
-0
lines changed
 

‎class meets.md

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
## class meets ##
2+
3+
> Summary: 2 students switched between in person and virtual school after `i` days of in person and `v` days of virtual, both starting in person first. Assuming each month is 30 days with 12 months, how many times do they "meet" (both being in person or both being virtual) given a starting and ending date?
4+
5+
> Solution: Create 3 arrays of whether or not there is school, the schedule of student1 (switching between in person and virtual), and the schedule of student2 (switching between in person and virtual). Parse through all of them at the same time and if they meet on a school day and both having the same type of school, increase a counter by one, otherwise, keep parsing.
6+
7+
Code:
8+
```
9+
def calendar(m1, d1, m2, d2, i1, i2, v1, v2):
10+
td1 = m1*30+d1
11+
td2 = m2*30+d2
12+
```
13+
> td1 is the total number of days from M0, D0 (starting date).
14+
> td2 is the total number of days from M0, D0 (ending date).
15+
```
16+
student1 = []
17+
student2 = []
18+
calendar_list = []
19+
for x in range(52):
20+
for z in range(5):
21+
calendar_list.append('s')
22+
for z in range(2):
23+
calendar_list.append('n')
24+
```
25+
> calendar_list is the total calendar year starting from M0, D0 switching between 5 days of `s`chool (weekdays) and 2 days of `n`o school (weekends).
26+
```
27+
for before in range(td1):
28+
calendar_list[before] = 'n'
29+
for after in range(364-td2):
30+
calendar_list[-after] = 'n'
31+
```
32+
> Fill the days before the starting date and after the ending date with `n` because we don't want to count those anyways.
33+
```
34+
for x in range(360//(i1+v1)+1):
35+
for z in range(i1):
36+
student1.append('i')
37+
for z in range(v1):
38+
student1.append('v')
39+
for x in range(360//(i2+v2)+1):
40+
for z in range(i2):
41+
student2.append('i')
42+
for z in range(v2):
43+
student2.append('v')
44+
```
45+
> student1 and student2 are lists for the alternating for in person and virtual for student1 and student2, respectively.
46+
> Side note: These lists can be any length longer than calendar_list or 360 days because it doesn't matter how long they are.
47+
```
48+
for x in range(len(student1)-5//7):
49+
student1.insert(x*5+(x-1)*2,'n')
50+
student1.insert(x*5+(x-1)*2,'n')
51+
for x in range(len(student2)-5//7):
52+
student2.insert(x*5+(x-1)*2,'n')
53+
student2.insert(x*5+(x-1)*2,'n')
54+
```
55+
> Remember weekends? We need to add them in for each student's list cycle (there's a `(x-1)*2` in there because adding 2 `n` in there increases the total length of the list so otherwise, the indexing is messed up).
56+
```
57+
counter = 0
58+
for x in range(len(calendar_list)):
59+
if calendar_list[x] == 's':
60+
if student1[x] == 'i' and student2[x] == 'i':
61+
counter += 1
62+
elif student1[x] == 'v' and student2[x] == 'v':
63+
counter += 1
64+
print(counter)
65+
```
66+
> We loop through each day in calendar_list which is 360 days (see, the student lists' length don't matter) and if there is school and student1 "meets" student2 (being in the same school type), we increase the counter by 1. Then we print the total number of meets.
67+
68+
69+
> Remember calendar(m1, d1, m2, d2, i1, i2, v1, v2) and actually run it.
70+
> `calendar(5,6,8,3,3,4,3,6)` outputs `30`
71+
72+
> This is a function so you could automate it and plug it into pwntools if you so desire.
73+

‎fib2.md

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
## Extended-fibonacci-sequence2 ##
2+
3+
> Summary: Using a fib sequence, with n<sub>0</sub> being `4` and n<sub>1</sub> being `5` instead of the usual `1` and `1`. There is a second sequence `S` where S<sub>n</sub> = S<sub>n-1</sub> + F<sub>0</sub> and S<sub>0</sub> = F<sub>0</sub> which is just `4`. Return the last 10 digits of the sum of all values of S<sub>0</sub> to S<sub>i</sub>, basically: $$\sum_{i=0}^{n} S_i$$
4+
5+
> Solution: Create a fib sequence that starts from `4` and `5` which you should have from the previous fib challenge and then link that to the S sequence such that the S sequences relies on the F sequence for output. (Because normal recursion will crash the system, use memoization). Generate the sums and string format to get the last 10 digits.
6+
7+
Code:
8+
```
9+
from pwn import *
10+
import re
11+
12+
cacheF = {}
13+
cacheE = {}
14+
def fibonacci(n):
15+
if n in cacheF:
16+
return cacheF[n]
17+
if n == 0:
18+
return 4
19+
elif n == 1:
20+
return 5
21+
else:
22+
result = fibonacci(n-1) + fibonacci(n-2)
23+
cacheF[n] = result
24+
return result
25+
```
26+
> This is the normal fib sequences `F`. Take note of the `cacheE` and `cacheF`, they are part of the memoization technique.
27+
28+
```
29+
def extend(n):
30+
if n in cacheE:
31+
return cacheE[n]
32+
33+
if n == 0:
34+
return 4
35+
else:
36+
result = fibonacci(n) + extend(n-1)
37+
cacheE[n] = result
38+
return result
39+
```
40+
> Extend is just the `S` sequence being generated from the results of `F`.
41+
42+
```
43+
r = remote('extended-fibonacci-sequence-2.hsc.tf', 1337)
44+
for i in range(100):
45+
print(r.recvuntil('!\n'))
46+
n = r.recvline().decode("utf-8").strip()
47+
```
48+
> Set up a pwntools connection to the server so we can automate it.
49+
50+
```
51+
print(n)
52+
if 'flag' in n:
53+
print(r.recvall())
54+
break
55+
n = int(re.sub("[^0-9]", "", n))
56+
extend(n)
57+
ret = sum(list(cacheE.values())[:n])+4
58+
print(ret)
59+
if len(str(ret)) > 10:
60+
r.sendline(str(ret)[-10:])
61+
else:
62+
r.sendline(str(ret))
63+
print(r.recvline())
64+
```
65+
> Format the string from the `S` sequence and return it to the server, rinse and repeat.

‎lupus.md

+118
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
## Canis-lupus-familiaris-bernardus ##
2+
3+
> Summary: They got lazy with the namings and just put taxamonies of random animals. `Spam()` generates a random list of 16 chars, if there is any character `JOUX`, it is flagged as `True`, otherwise it is `False`. `Valid()` tests if all the characters in a string are not `JOUX`. `Enc()` and `Dec()` just encode and decode a string using AES. The loop of 100 asks us to guess whether or not a string has been `changed` (ie if it has `JOUX` or not) and then asks us to make it a valid peptide. Making it a valid peptide means changing the IV such that when the string with `JOUX` is encoded with the original IV, when you decode it with your inputed IV, it returns a a string with all ascii characters without `JOUX`.
4+
5+
> Solution: First, we need to find out if the string was `changed` or not which is easy because if it has `JOUX`, it is changed, otherwise it isn't. Now to create a valid peptide from the changed peptides. Because AES translates each character in the message with the IV (the key is irrelevant here because it nevers changes) we just need to modify the same index if the IV until it returns a valid peptide.
6+
7+
Code:
8+
```
9+
from pwn import *
10+
import string
11+
from Crypto.Cipher import AES
12+
from Crypto.Random import *
13+
from Crypto.Util.Padding import *
14+
15+
def enc(key, iv, pt):
16+
cipher = AES.new(key, AES.MODE_CBC, iv)
17+
return cipher.encrypt(pad(pt, AES.block_size))
18+
19+
def dec(key, iv, ct):
20+
try:
21+
cipher = AES.new(key, AES.MODE_CBC, iv)
22+
return unpad(cipher.decrypt(ct), AES.block_size)
23+
except (ValueError, KeyError):
24+
print("THAT IS NOT A VALID PEPTIDE.")
25+
exit(1)
26+
```
27+
28+
> Easy stuff just copy and pasted from the original document.
29+
30+
```
31+
32+
def fix_iv(iv,text):
33+
key = b'bbbbbbbbbbbbbbbb'
34+
text = list(str(text))
35+
if 'J' in text:
36+
i = text.index('J')
37+
elif 'O' in text:
38+
i = text.index('O')
39+
elif 'U' in text:
40+
i = text.index('U')
41+
elif 'X' in text:
42+
i = text.index('X')
43+
text = ''.join(text)
44+
counter = 0
45+
iv = hex(int(iv,16))[2:]
46+
for x in range(5):
47+
try:
48+
print(str(hex(int(iv[i*2+1],16)^1)))
49+
trial = iv[0:i*2+1]+str(hex(int(iv[i*2+1],16)^1))[2:]+iv[i*2+2:]
50+
trial_dec = dec(key,bytes.fromhex(trial),enc(key,bytes.fromhex(iv), bytes(text,'ascii')))
51+
print(trial_dec)
52+
if b'J' not in trial_dec and b'O' not in trial_dec and b'U' not in trial_dec and b'X' not in trial_dec:
53+
print('correct iv: ',trial)
54+
return trial
55+
except:
56+
pass
57+
```
58+
> `Fix_iv` sets a random key (make sure it's 16 bytes long) and finds the index for `JOUX`. Then we just try changing that index on the IV from 2 ascii characters behind and 2 ascii characters in front (expand the formatting stuff if you need to it's a bit confusing). Test each one out and if they work, return the fixed IV.
59+
```
60+
r = remote('canis-lupus-familiaris-bernardus.hsc.tf', 1337)
61+
62+
for i in range(100):
63+
print(i)
64+
print(r.recvuntil('Is '))
65+
pep = r.recvuntil(' ').strip().decode('utf-8')
66+
print(pep)
67+
# JOUX
68+
if pep.find('J') != -1:
69+
r.sendline('F')
70+
pos = pep.find('J')
71+
r.recvuntil('IV:')
72+
iv = r.recvline().strip()
73+
print(iv)
74+
iv = fix_iv(iv, pep)
75+
print(iv)
76+
r.sendline(iv)
77+
'''
78+
iv = r.recvline().strip()
79+
ivb = iv.decode('hex')
80+
ivb = ivb[:pos] + chr(ord(ivb[pos])^1) + ivb[pos+1:]
81+
r.sendline(ivb.encode('hex'))
82+
'''
83+
elif pep.find('O') != -1:
84+
r.sendline('F')
85+
pos = pep.find('O')
86+
r.recvuntil('IV:')
87+
iv = r.recvline().strip()
88+
print(iv)
89+
iv = fix_iv(iv, pep)
90+
print(iv)
91+
r.sendline(iv)
92+
elif pep.find('U') != -1:
93+
r.sendline('F')
94+
pos = pep.find('U')
95+
r.recvuntil('IV:')
96+
iv = r.recvline().strip()
97+
print(iv)
98+
iv = fix_iv(iv, pep)
99+
print(iv)
100+
r.sendline(iv)
101+
elif pep.find('X') != -1:
102+
r.sendline('F')
103+
pos = pep.find('X')
104+
r.recvuntil('IV:')
105+
iv = r.recvline().strip()
106+
print(iv)
107+
iv = fix_iv(iv, pep)
108+
print(iv)
109+
r.sendline(iv)
110+
else:
111+
r.sendline('T')
112+
try:
113+
print(r.recvline())
114+
except:
115+
print('shit')
116+
r.interactive()
117+
```
118+
> Connect to the server using pwntools to automate it and check for `JOUX` in each string, if there is, fix the IV and return.

‎not-really-math.md

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
## not-really-math ##
2+
3+
> Summary: change the order of operations in a math formula with only addition (a) and multiplication (m) to having addition operations first and mulitplication operations second.
4+
5+
Sample Input:
6+
7+
2m3a19m2a38m1
8+
9+
Sample Output:
10+
11+
1760
12+
13+
Explanation:
14+
15+
2\*(3+19)\*(2+38)\*1 = 1760
16+
17+
18+
> Code Concept:
19+
>
20+
> Add `(` and `)` around the numbers that should be added and change `a` to `+` and `m` to `*`
21+
>
22+
> Then plug into python calculator to solve
23+
24+
```
25+
import sys
26+
27+
print(sys.argv\[1\])
28+
29+
new = list(sys.argv\[1\])
30+
31+
l = \["m","a"\]
32+
33+
c = 0
34+
35+
while c < len(new)-1:
36+
37+
if new\[c\] not in l and new\[c+1\] not in l:
38+
39+
new\[c\] += new\[c+1\]
40+
41+
del new\[c+1\]
42+
43+
c -= 1
44+
45+
c += 1
46+
47+
c = 0
48+
49+
while c < len(new):
50+
51+
if new\[c\] == "a":
52+
53+
if new\[c-1\] != ")":
54+
55+
new.insert(c-1,"(")
56+
57+
new.insert(c+3,")")
58+
59+
new\[c+1\] = "+"
60+
61+
else:
62+
63+
new.insert(c-1,"+")
64+
65+
new.insert(c, new\[c+2\])
66+
67+
del new\[c+2\]
68+
69+
del new\[c+2\]
70+
71+
elif new\[c\] == "m":
72+
73+
new\[c\] = "\*"
74+
75+
c += 1
76+
for x in new:
77+
78+
if x != "(" and x!= ")" and x!= "+" and x!="\*":
79+
80+
x = int(x)
81+
82+
new = ''.join(new)
83+
84+
print(eval(new)%(pow(2,32)-1))
85+
86+
```

‎zkp.md

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
## zkp ##
2+
3+
> Summary: A 3SAT problem generator generates 3SAT problems, but the server makes some of them nonSAT, our job is to figure out which ones were modded to be nonSAT and which ones are still SAT (not modded). We are given a finite amount of tests to request for a n<sup>th</sup> clause to see, though after each request, the whole formula is shuffled. We have to solve for `t` number of trials with a total of `m` clauses and `n` literals. We need to have a success rate of at least 75% (guessing whether or not the formula was modded or not).
4+
>
5+
> 3SAT: 3SAT is a type of SAT which always has 3 literals per clause. Each literal is a separate boolean and each clause is a conjunction of literals (3 in the case of 3SAT). A formula is considered SAT if any combination of booleans can make the output `True`. Each literal is connected with the other literals by an `OR` gate while each clause is connected by an `AND` gate.
6+
>
7+
> 3SAT Ex: `(T OR T OR F) AND (F OR T OR F) AND (F OR F OR T)` is SAT solvable because the output is `T`
8+
>
9+
> 3SAT Ex: `(T OR T OR F) AND (F OR T OR F) AND (F OR F OR F)` is not SAT solvable because the output is `F`
10+
>
11+
> Theory: If each clause is connected by an `AND` gate, that means that each internal clause must output `T`, otherwise the whole answer becomes `F`. If each clause must be `T` then calculating all the possible combinations:
12+
>
13+
```
14+
(T OR T OR T) = T
15+
(T OR T OR F) = T
16+
(T OR F OR T) = T
17+
(T OR F OR F) = T
18+
(F OR T OR T) = T
19+
(F OR T OR F) = T
20+
(F OR F OR T) = T
21+
(F OR F OR F) = F
22+
```
23+
> The only combination that doesn't work is `FFF` which means all we need to do it look out for `FFF` and it is definitely nonSAT.
24+
>
25+
> Solution: The number of literals and clauses are basically irrelevant. We request 10 times for a random clause `(1<random_clause<m)` and if the combination `(F OR F OR F)` is one of them, we immediately guess `false` or nonSAT. If we have reached the end of 10 requests and have not encountered `(F OR F OR F)`, we guess either `false` or `true`. Statistically, that 75% should hold true because guessing at total random gives us 50%, the extra 25% is added by using this formula. If it doesn't work the first time, run it again because it still can fail.
26+
>
27+
> Code (uncomment some of the print statement if you wanna see what's happening):
28+
> Disclaimer: This code isn't fully functional and sometimes crashes but it should work after a few tries. If you wanna help us debug that would be nice :D.
29+
```
30+
from pwn import *
31+
import random
32+
33+
34+
def attempt():
35+
r = remote('zkp.hsc.tf', 1337)
36+
l = ['true','true','false']
37+
print(r.recvuntil(f'==\n'))
38+
trials = int(r.recvline().decode('utf-8'))
39+
print('trials: ',trials)
40+
for t in range(trials):
41+
n = r.recvline().decode('utf-8').strip()
42+
#print('N: ',n)
43+
m = r.recvline().decode('utf-8').strip()
44+
#print('M: ',m)
45+
permuted = r.recvline().decode('utf-8').strip()
46+
#print('permuted: ',permuted)
47+
i = str(random.randint(0,int(m)//2))
48+
#print('randint: ',i)
49+
r.sendline(i)
50+
51+
literals = r.recvline().decode('utf-8').strip()
52+
#print('first literals: ',literals)
53+
absolute = True
54+
for z in range(15):
55+
r.sendline('next')
56+
#print('sent next')
57+
permuted = r.recvline().decode('utf-8').strip()
58+
#print('permuted: ',permuted)
59+
i = str(random.randint(0,int(m)))
60+
r.sendline(i)
61+
literals = r.recvline().decode('utf-8').strip()
62+
#print(literals,type(literals))
63+
if literals == ': [False, False, False]':
64+
absolute = False
65+
#print('absolutely false')
66+
break
67+
print('finished trial',t,'/',trials)
68+
if absolute == False:
69+
guess = 'false'
70+
else:
71+
guess = random.choice(l)
72+
print('guess',guess)
73+
r.sendline(guess)
74+
#r.sendline(ret)
75+
result = r.recvline().decode('utf-8').strip()
76+
print(result)
77+
try:
78+
result = r.recvline().decode('utf-8').strip()
79+
print(result)
80+
except:
81+
print('one more down')
82+
for x in range(10):
83+
try:
84+
attempt()
85+
except:
86+
pass
87+
```

0 commit comments

Comments
 (0)
Please sign in to comment.