---
# System prepended metadata

title: WU KMACTF 2023 lần 1

---

# WU KMACTF 2023
## Crypto
### Schnorr
![](https://hackmd.io/_uploads/BJDFA9luh.png)
chal.py
```python=
import random
import time
from flag import FLAG

p = 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff
g = 0x2
q = 0x7fffffff800000008000000000000000000000007fffffffffffffffffffffff
assert pow(g, q, p) == 1


def challenge(rounds=64):
    random.seed(int(time.time()))
    x = int.from_bytes(FLAG, "big")
    y = pow(g, x, p)
    print("Prove you know x, such that pow({0}, x, {1}) == {2}".format(g, p, y))
    try:
        for i in range(rounds):
            print("[+] Round {0}/{1}".format(i+1, rounds))
            t = int(input("t = "))
            c = random.randint(1, q-1)
            print("c = {0}".format(c))
            s = int(input("s = "))
            if pow(g, s, p) == (t*pow(y, c, p)) % p:
                continue
            else:
                return False
    except:
        return False

    return True


if __name__ == "__main__":
    is_verified = challenge()
    if is_verified:
        print(FLAG)
    else:
        print("Better luck next time, hackers!")

```
https://en.wikipedia.org/wiki/Proof_of_knowledge#Schnorr_protocol
- Trong chall này thì sử dụng Schnorr protocol, và yêu cầu nhập `t` và `s` thỏa mãn điều kiện để vượt qua thử thách 64 lần để đạt được flag. 
- Để thỏa điều kiện `pow(g, s, p) == (t * pow(y, c, p)) % p` thì mình chọn s bằng bất kì số nào từ `(1,p-1)` và tính `t`= y^-c từ `c` đoán được từ `random.seed(int(time.time()))`.


solved.py:
```python3=
from pwn import *
import random
import time
p = 115792089210356248762697446949407573530086143415290314195533631308867097853951
g = 2
q = 57896044605178124381348723474703786765043071707645157097766815654433548926975
y = 61252110398173126436323285216974857619112851968123774381188703220254043681646


r=remote("103.163.25.143",60124)
random.seed(int(time.time()))

data = r.recv()
print(data)
s=p-1
for i in range(64):
    c = random.randint(1, q-1)
    t=pow(y,-c,p)
    r.sendline(str(t).encode())
    print(r.recv().decode())
    r.sendline(str(s).encode())
    print(r.recv().decode())
r.interactive()
```

### SSS Voting I
![](https://hackmd.io/_uploads/Hkr2ImZu2.png)
main.go:
```go=
package main

import (
	"encoding/hex"
	"fmt"
	"log"
	"math/big"
	"math/rand"
	"net"
	"os"
)

const (
	HOST = "localhost"
	PORT = "1337"
	TYPE = "tcp"
	FLAG = "KMACTF{flag}"
)

func tamper(conn net.Conn, original []*big.Int) {
	conn.Write([]byte("Original votes (each vote is encoded in 64 hex characters):\n"))
	for _, ori := range original {
		buf := make([]byte, 32)
		ori.FillBytes(buf)
		conn.Write([]byte(hex.EncodeToString(buf)))
	}

	conn.Write([]byte("\nTampered votes:\n"))
	buf := make([]byte, 64*len(original))
	_, err := conn.Read(buf)
	if err != nil {
		conn.Close()
		return
	}

	for idx, tamper := range original {
		_, ok := tamper.SetString(string(buf[idx*64:idx*64+64]), 16)
		if !ok {
			conn.Close()
			return
		}
	}
}

func main() {
	listen, err := net.Listen(TYPE, HOST+":"+PORT)
	if err != nil {
		log.Fatal(err)
		os.Exit(1)
	}
	// close listener
	defer listen.Close()
	for {
		conn, err := listen.Accept()
		if err != nil {
			log.Fatal(err)
			os.Exit(1)
		}
		go handleRequest(conn)
	}
}

func handleRequest(conn net.Conn) {
	n := 10 // number of voters
	k := 5  // number of authorities
	t := 2  // `threshold` the scheme requires t + 1 honest authorities to derive the final result

	conn.Write([]byte("[+] Public ID of available authorities:\n"))
	authorities := make([]*authority, k)
	for i := 0; i < k; i++ {
		authorities[i] = init_authority()
		conn.Write([]byte(fmt.Sprintf("%d\n", authorities[i].id)))
	}

	voters := make([]*voter, n)
	for i := 0; i < n; i++ {
		voters[i] = init_voter(t, rand.Intn(2) == 1)
		voters[i].votes = make([]*big.Int, k)
		for j := 0; j < k; j++ {
			voters[i].votes[j] = voters[i].eval(authorities[j].id)
		}
	}

	conn.Write([]byte("[+] One voter is being hacked.\n"))
	tamper(conn, voters[0].votes)

	// voters send votes to authorities
	for i := 0; i < k; i++ {
		votes := make([]*big.Int, n)
		for j := 0; j < n; j++ {
			votes[j] = voters[j].votes[i]
		}
		authorities[i].votes = votes
	}

	rand.Shuffle(len(authorities), func(i, j int) {
		authorities[i], authorities[j] = authorities[j], authorities[i]
	})

	ids := get_ids(authorities[:t+1])
	votes := get_votes(authorities[:t+1])
	result := lagrange_interpolate(ids, votes)

	if result.Cmp(big.NewInt(1337)) == 0 {
		conn.Write([]byte(fmt.Sprintf("[*] There are 1337 votes, seems like someone is hacking! :( The flag is %s\n", FLAG)))
	} else {
		if result.Cmp(big.NewInt(int64(n))) != 1 {
			conn.Write([]byte(fmt.Sprintf("[*] We got %d yes from everyone.\n", result)))
		} else {
			conn.Write([]byte(fmt.Sprintf("[*] We got %d yes. Suspicious...\n", result)))
		}
	}
	conn.Close()
}

```
operator.go:
```go=
package main

import (
	"crypto/rand"
	"math/big"
)

type (
	// voter will submit votes
	voter struct {
		poly  []*big.Int
		agree bool
		votes []*big.Int
	}

	// authority will count the votes
	authority struct {
		id    *big.Int
		votes []*big.Int
	}
)

// random polynomial of degree d
func init_voter(d int, agree bool) *voter {
	poly := make([]*big.Int, d+1)
	poly[0] = big.NewInt(0)
	if agree {
		poly[0] = big.NewInt(1)
	}

	for i := 1; i <= d; i++ {
		buf := make([]byte, 32)
		rand.Read(buf)
		poly[i] = new(big.Int).SetBytes(buf)
	}
	return &voter{poly: poly, agree: agree}
}

func init_authority() *authority {
	buf := make([]byte, 32)
	rand.Read(buf)
	return &authority{id: new(big.Int).SetBytes(buf)}
}

func (voter *voter) eval(authority_id *big.Int) *big.Int {
	p := new(big.Int).SetBytes([]byte{255, 255, 255, 255, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255})
	vote := big.NewInt(0)
	id := big.NewInt(1)
	for _, coef := range voter.poly {
		tmp := new(big.Int).Mul(coef, id)
		vote.Add(vote, tmp)
		id.Mul(id, authority_id)
		id.Mod(id, p)
	}
	vote.Mod(vote, p)
	return vote
}

func (authority *authority) count_votes() *big.Int {
	p := new(big.Int).SetBytes([]byte{255, 255, 255, 255, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255})
	result := big.NewInt(0)
	for _, vote := range authority.votes {
		result.Add(result, vote)
	}
	result.Mod(result, p)
	return result
}

func get_ids(authorities []*authority) []*big.Int {
	ids := make([]*big.Int, len(authorities))
	for i := 0; i < len(authorities); i++ {
		ids[i] = authorities[i].id
	}
	return ids
}

func get_votes(authorities []*authority) []*big.Int {
	votes := make([]*big.Int, len(authorities))
	for i := 0; i < len(authorities); i++ {
		votes[i] = authorities[i].count_votes()
	}
	return votes
}

func lagrange_interpolate(ids, votes []*big.Int) *big.Int {
	p := new(big.Int).SetBytes([]byte{255, 255, 255, 255, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255})
	if len(ids) != len(votes) {
		return nil
	}

	sum := big.NewInt(0)
	for i := 0; i < len(votes); i++ {
		tmp := votes[i]
		for j := 0; j < len(ids); j++ {
			if i != j {
				neg := new(big.Int).Neg(ids[j])
				neg.Add(neg, p)
				tmp.Mul(tmp, neg)
				neg.Add(neg, ids[i])
				neg.ModInverse(neg, p)
				tmp.Mul(tmp, neg)
			}
		}
		sum.Add(sum, tmp)
		sum.Mod(sum, p)
	}
	return sum
}

```
- Bài này cho hai file golang, hàm `handleRequest`  nó tạo phiếu bầu từ các người bỏ phiếu và gửi cho các tổ chức đếm phiếu tương ứng. Hàm `tamper` được gọi để can thiệp vào phiếu bầu của một người bỏ phiếu cụ thể.
Yêu cầu chúng ta nhập vào một `Tampered votes` ,
nó sử dụng phương pháp nội suy Lagrange để khôi phục các giá trị votes ban đầu. Sau đó được so sánh với 1337 nếu bằng thì sẽ trả về flag.
- Việc của chúng ta là can thiệp vào số phiếu bầu sao cho thỏa điều kiện bằng 1337 số phiếu bầu.Để tính `Tampered votes` ta thực hiện phép tính `(votes + 1332) % (2 ** 256)` và gửi cho sever để nhận flag
solved.py:
```python=
while True:
    r = connect('103.163.25.143', 60125)

    p = 115792089210356248762697446949407573530086143415290314195533631308867097853951
    (r.recv())
    (r.recvline_startswith(b'Original votes '))
    votes = r.recvline().strip().decode()
    def compute_tampered_votes(votes):
        tampered = ''
        for i in range(5):
            tampered += str(hex((int(votes[:64], 16) + 1332)%(2**256))[2:].zfill(64))
            votes = votes[64:]
        return tampered

    tampered_votes = compute_tampered_votes(votes)
    # print(tampered_votes)
    (r.recv())
    r.send(tampered_votes.encode())
    flag=r.recv().decode()
    print(flag)
    if 'KMACTF' in flag:
        break
    r.close()

```

### SSS Voting II
![](https://hackmd.io/_uploads/H1gH5Q-uh.png)
main.go
```go=
package main

import (
	"encoding/hex"
	"fmt"
	"log"
	"math/big"
	"math/rand"
	"net"
	"os"
)

const (
	HOST = "localhost"
	PORT = "1337"
	TYPE = "tcp"
	FLAG = "KMACTF{flag}"
)

func tamper(conn net.Conn, original []*big.Int) {
	conn.Write([]byte("Original votes (each vote is encoded in 64 hex characters):\n"))
	for _, ori := range original {
		buf := make([]byte, 32)
		ori.FillBytes(buf)
		conn.Write([]byte(hex.EncodeToString(buf)))
	}

	conn.Write([]byte("\nTampered votes:\n"))
	buf := make([]byte, 64*len(original))
	_, err := conn.Read(buf)
	if err != nil {
		conn.Close()
		return
	}

	for idx, tamper := range original {
		_, ok := tamper.SetString(string(buf[idx*64:idx*64+64]), 16)
		if !ok {
			conn.Close()
			return
		}
	}
}

func main() {
	listen, err := net.Listen(TYPE, HOST+":"+PORT)
	if err != nil {
		log.Fatal(err)
		os.Exit(1)
	}
	// close listener
	defer listen.Close()
	for {
		conn, err := listen.Accept()
		if err != nil {
			log.Fatal(err)
			os.Exit(1)
		}
		go handleRequest(conn)
	}
}

func handleRequest(conn net.Conn) {
	n := 10 // number of voters
	k := 5  // number of authorities
	t := 2  // `threshold` the scheme requires t + 1 honest authorities to derive the final result

	conn.Write([]byte("[+] Public ID of available authorities:\n"))
	authorities := make([]*authority, k)
	for i := 0; i < k; i++ {
		authorities[i] = init_authority()
		conn.Write([]byte(fmt.Sprintf("%d\n", authorities[i].id)))
	}

	voters := make([]*voter, n)
	for i := 0; i < n; i++ {
		voters[i] = init_voter(t, rand.Intn(2) == 1)
		voters[i].votes = make([]*big.Int, k)
		for j := 0; j < k; j++ {
			voters[i].votes[j] = voters[i].eval(authorities[j].id)
		}
	}

	// voters send votes to authorities
	for i := 0; i < k; i++ {
		votes := make([]*big.Int, n)
		for j := 0; j < n; j++ {
			votes[j] = voters[j].votes[i]
		}
		authorities[i].votes = votes
	}

	rand.Shuffle(len(authorities), func(i, j int) {
		authorities[i], authorities[j] = authorities[j], authorities[i]
	})

	conn.Write([]byte(fmt.Sprintf("[+] Authority %d is being hacked.\n", authorities[0].id)))
	tamper(conn, authorities[0].votes)

	ids := get_ids(authorities[:t+1])
	votes := get_votes(authorities[:t+1])
	result := lagrange_interpolate(ids, votes)

	if result.Cmp(big.NewInt(1337)) == 0 {
		conn.Write([]byte(fmt.Sprintf("[*] There are 1337 votes, seems like someone is hacking! :( The flag is %s\n", FLAG)))
	} else {
		if result.Cmp(big.NewInt(int64(n))) != 1 {
			conn.Write([]byte(fmt.Sprintf("[*] We got %d yes from everyone.\n", result)))
		} else {
			conn.Write([]byte(fmt.Sprintf("[*] We got %d yes. Suspicious...\n", result)))
		}
	}
	conn.Close()
}

```
operator.go:
```go=
package main

import (
	"crypto/rand"
	"math/big"
)

type (
	// voter will submit votes
	voter struct {
		poly  []*big.Int
		agree bool
		votes []*big.Int
	}

	// authority will count the votes
	authority struct {
		id    *big.Int
		votes []*big.Int
	}
)

// random polynomial of degree d
func init_voter(d int, agree bool) *voter {
	poly := make([]*big.Int, d+1)
	poly[0] = big.NewInt(0)
	if agree {
		poly[0] = big.NewInt(1)
	}

	for i := 1; i <= d; i++ {
		buf := make([]byte, 32)
		rand.Read(buf)
		poly[i] = new(big.Int).SetBytes(buf)
	}
	return &voter{poly: poly, agree: agree}
}

func init_authority() *authority {
	buf := make([]byte, 32)
	rand.Read(buf)
	return &authority{id: new(big.Int).SetBytes(buf)}
}

func (voter *voter) eval(authority_id *big.Int) *big.Int {
	p := new(big.Int).SetBytes([]byte{255, 255, 255, 255, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255})
	vote := big.NewInt(0)
	id := big.NewInt(1)
	for _, coef := range voter.poly {
		tmp := new(big.Int).Mul(coef, id)
		vote.Add(vote, tmp)
		id.Mul(id, authority_id)
		id.Mod(id, p)
	}
	vote.Mod(vote, p)
	return vote
}

func (authority *authority) count_votes() *big.Int {
	p := new(big.Int).SetBytes([]byte{255, 255, 255, 255, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255})
	result := big.NewInt(0)
	for _, vote := range authority.votes {
		result.Add(result, vote)
	}
	result.Mod(result, p)
	return result
}

func get_ids(authorities []*authority) []*big.Int {
	ids := make([]*big.Int, len(authorities))
	for i := 0; i < len(authorities); i++ {
		ids[i] = authorities[i].id
	}
	return ids
}

func get_votes(authorities []*authority) []*big.Int {
	votes := make([]*big.Int, len(authorities))
	for i := 0; i < len(authorities); i++ {
		votes[i] = authorities[i].count_votes()
	}
	return votes
}

func lagrange_interpolate(ids, votes []*big.Int) *big.Int {
	p := new(big.Int).SetBytes([]byte{255, 255, 255, 255, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255})
	if len(ids) != len(votes) {
		return nil
	}

	sum := big.NewInt(0)
	for i := 0; i < len(votes); i++ {
		tmp := votes[i]
		for j := 0; j < len(ids); j++ {
			if i != j {
				neg := new(big.Int).Neg(ids[j])
				neg.Add(neg, p)
				tmp.Mul(tmp, neg)
				neg.Add(neg, ids[i])
				neg.ModInverse(neg, p)
				tmp.Mul(tmp, neg)
			}
		}
		sum.Add(sum, tmp)
		sum.Mod(sum, p)
	}
	return sum
}

```

- 
solved.py:
```
from pwn import *
p = 115792089210356248762697446949407573530086143415290314195533631308867097853951

while 1:
    s = connect('103.163.25.143', 60126)
    ids = []
    s.recvline_startswith(b'[+] Public ID of available authorities:')
    for i in range(5):
        ids.append(int(s.recvline().strip().decode()))

    id_hacked = int(s.recvline_startswith(b'[+] Authority').strip().decode().split(' ')[-4])
    ids.remove(id_hacked)
    
    tmp = (p - ids[1])*(p - ids[2]) % p
    tmp = tmp*pow((p - ids[1] + id_hacked)*(p - ids[2] + id_hacked), -1, p) % p
    
    s.recvline_startswith(b'Original votes ')
    votes = s.recvline().strip().decode()

    fake_votes = votes[:-64]
    fake_votes += str(hex(((int(votes[-64:], 16)) + 1333*pow(tmp, -1, p))%p))[2:].zfill(64)
    s.sendlineafter(b'Tampered votes:\n', fake_votes.encode())
    
    a = s.recv()
    print(a)
    if b'KMA' in a:
        s.interactive()
    s.close()
```
> KMACTF{c0ngr4ts!_h4ck3r_:grin:_:grin:_:grin:}



### Only Lord Can Go REVENGE
![](https://hackmd.io/_uploads/B17O3IB_2.png)
![](https://hackmd.io/_uploads/SyZw68B_n.png)
chall.py:
```python=
from Crypto.Util.number import *
import random

print(
"""
     )      (           (       )                   (       )                
  ( /(  (   )\ )  (     )\ ) ( /(   *   )  *   )    )\ ) ( /(             )  
  )\()) )\ (()/(  )\   (()/( )\())` )  /(` )  /((  (()/( )\())  (   (  ( /(  
|((_)\(((_) /(_)|((_)   /(_)|(_)\  ( )(_))( )(_))\  /(_)|(_)\   )\  )\ )(_)) 
|_ ((_)\___(_)) )\___  (_))   ((_)(_(_())(_(_()|(_)(_))__ ((_) ((_)((_|(_)   
| |/ ((/ __/ __((/ __| | |   / _ \|_   _||_   _| __| _ \ \ / / \ \ / /|_  )  
  ' < | (__\__ \| (__  | |__| (_) | | |    | | | _||   /\ V /   \ V /  / /   
 _|\_\ \___|___/ \___| |____|\___/  |_|    |_| |___|_|_\ |_|     \_/  /___|  
                                                                             
"""
)

m = 94472212093594626131047436978697575439604582025155253003497324934058676105592120465477333165162440542344704938026733015754449262871298725480530709273109987324093054515772972278276237630988938655113525659250415319555533704569076292929214171706312390225710667281502861122029038648478773963282271762064453388333
a = getPrime(128)
b = getPrime(256)
c = getPrime(512)
d = random.randrange(1,m)
e = random.randrange(1,m)

print("I will give u only 4 lucky numbers :>")
for i in range(4):
    y = (a*d + b*e + c) % m
    print(f"Lucky number {i+1}: {y}")
    e = d
    d = y

print("Now show off your guessing skills, ego ._.")

for i in range(23):
    y = (a*d + b*e + c) % m
    guess = int(input("Guess: "))
    if guess == y:
        print(f'Nai xuw !!! Remain: {23-i-1}/23')
    else:
        print("Luck is only for those who try, if you don't understand that, then get out !!!")
        exit(0)
    e = d
    d = y

print("WOW, I rly want how do u can guess all correctly, plz sharing w me :<")
print('KMACTF{mao_phac?}')
```




solved.py:
```python=
from pwn import *
from sage.all import *

r = remote('103.163.25.143', 60127)

y_arr = []
for i in range(4):
    r.recvuntil(f'Lucky number {i+1}: '.encode())
    y = int(r.recvline())
    y_arr.append(y)

m = 94472212093594626131047436978697575439604582025155253003497324934058676105592120465477333165162440542344704938026733015754449262871298725480530709273109987324093054515772972278276237630988938655113525659250415319555533704569076292929214171706312390225710667281502861122029038648478773963282271762064453388333
M = Matrix([
  [(y_arr[1] - y_arr[0])*(2**1024), 1, 0, 0], 
  [(y_arr[2] - y_arr[1])*(2**1024), 0, 1, 0], 
  [(y_arr[3] - y_arr[2])*(2**1024), 0, 0, (2**1024)], 
  [m*(2**1024), 0, 0, 0],
])

L = M.LLL()
b,a = abs(L[3][1]), abs(L[3,2])
c = (y_arr[3] - a*y_arr[2] - b*y_arr[1]) % m
print(c)

print(f'[+] FOUND a,b,c !!!')
print(f'[+] {a = }')
print(f'[+] {b = }')
print(f'[+] {c = }')

for i in range(23):
    y = (a*y_arr[-1] + b*y_arr[-2] + c) % m
    r.sendlineafter(b'Guess: ', str(y).encode())
    print(r.recvline())
    y_arr.append(y)

r.interactive()
```
> KMACTF{LLL_c0m3_b4ck_t0_KMA_?}