Recap UIUCTF 2023 - Team 42Roma

Corny Kernel Challenge

alt text Available files

  • pwnymodule.c

Click here for more info

Walktrough of my solution (which is pretty bad, actually):

  • To connect to the machine, use the given command trough socat:
socat file:$(tty),raw,echo=0 tcp:corny-kernel.chal.uiuc.tf:1337

After checcking all the files available on the machine, I noticed a file called pwnymodule.ko.gz in the /root directory. This file turned out to be a Kernel Module and could be live-mounted live on the kernel (which is the purpose of this challenge).

  • To mount the kernel module, run this command:
insmod pwnymodule.ko.gz
  • Once the module is mounted, I could check the kernel logs by running this command:
dmesg

I noticed that the logs displayed the first part of the flag. Then, I tried to unmount the module to see if anything would change.

  • To unmount the kernel module, run this command:
rmmod pwnymodule.ko.gz

After that, I ran the dmesg command again, and boom, the second part of the flag appeared. So now i have both the first and second parts of the flag.

[flag] = uiuctf{m4ster_k3rNE1_haCk3r}**

[extra] Initially, I thought that to obtain the flag, I had to remove the file “init” located in the root directory. Well, that turned out to be false, but I wanted to mention it anyway.

[more info]

I’ll add some links once i find some good writeups.


Group Project Challenge

alt text Available files

  • chal.py

Click here for more info

Walktrough of my solution (which is also pretty bad, actually)

The pourpose of this challenge was to use the group theory maths and (from what i understood) the Lagrange’s theorem.

The basic idea of the challenge is that you get the flag encrypted in c, and to decrypt it, you need to force the final result to be 1, which can be achieved by choosing the value of k.

If we examine the given code, we can see that someting happens when they check the value of k, particularly when k = p - 1.

In facts if k = p - 1 that means that after some algebraic operations and regardless the values of a and b, the exponent will always be a multiple of p - 1.

It can be rappresent as: (p - 1) * a * b.

Thanks to this, we can force S to become 1, according to group theory, specifically Lagrange’s theorem we have: g^(p-1) \mod p = 1 Because the group has order p - 1.

In this case if we force k = p - 1 we get:

  • S = g^(a * b * k) \mod p
  • = g^(a * b * (p-1)) \mod p
  • = (g^(p-1))^(a * b) \mod p
  • = 1^(a * b) \mod p
  • = 1

let’s see my specific case

  • To connect to the machine, use the given command through nc:
nc group.chal.uiuc.tf 1337

This is an example run where we choose k = p - 1

== proof-of-work: disabled ==
[$] Did no one ever tell you to mind your own business??
[$] Public:
[$]     g = 2
[$]     p = 123550563549747490323249224338990831394408051910991173735163283881290684423205314178830285306348019042127955168105946500849992929461306092791621619837542285563398201676541157481311715881882861461771386482605615740025776697545491552863159651061852777469798729628428268198459861272156418110367594843550743172627
[$]     A = 65577571120208990271365027516450216371270903165222652333226308026118839957307253811739762319146299166577506464436196113831495358295414487806901676838911064532591294232195578279790096365970082755598631058932069218146713938218135724446862334581120056129894062668713758501672608059247131378197566441717688794719
[$] Choose k = 123550563549747490323249224338990831394408051910991173735163283881290684423205314178830285306348019042127955168105946500849992929461306092791621619837542285563398201676541157481311715881882861461771386482605615740025776697545491552863159651061852777469798729628428268198459861272156418110367594843550743172626
[$] Ciphertext using shared 'secret' ;)
[$]     c = 31383420538805400549021388790532797474095834602121474716358265812491198185235485912863164473747446452579209175051706

If we try multiples times to put k = p - 1 we always get the same c value. This is because each time, S is reduced to 1, resulting in the same cipher value.

We can now decypher the flag using the provided file for understanding the cryptography used.:

S = 1
key = hashlib.md5(long_to_bytes(S)).digest()
cipher = AES.new(key, AES.MODE_ECB)

#Then we go from number to encrypted bytes. Note the 48 comes from the fact that 16 * 3 = 48.

c = 31383420538805400549021388790532797474095834602121474716358265812491198185235485912863164473747446452579209175051706
c = c.to_bytes(48, 'big')

#Finally we decrypt the string and remove the padding (encryption stuff).

p = cipher.decrypt(c)
p = unpad(p, 16)

#Voilà, our flag.
print(p)

[flag] = uiuctf{brut3f0rc3_a1n’t_s0_b4d_aft3r_all!!11!!}**

[extra] (҂◡_◡) ᕤ

[more info]

I’ll add some links once i find some good writeups.


Special thanks to the 42Roma Cybersecurity Club for their time and support, looking forward to the next CTFs!