NCTF2022-复现

NCTF2022-复现

比赛题目

NCTF2022

比赛总结

本次比赛,web还是一无所获,自己还是差的很多。反观misc,这次比赛六道杂项题,做出来两道,然后在核对大佬们的wp后发现自己的思路完全正确,可惜的是自己不会写脚本。总的,本次比赛收获挺大的,做misc的思路更上了一步。个人感觉,这次misc是我做过最有意思的一次,非常好玩。

Misc

Signin

程序设计实验作业,但是签到题(听zys说建议把终端字体调小一点并且只需要输入一串来自35年前的神秘秘籍

神秘秘籍:上上下下左右左右ba,可以直接得到flag
在这里插入图片描述NCTF{VVe1c0m3_T0_NCTF_2022!!!}

另一种解法
在这里插入图片描述这道题,ida不太会用,先把参考的wp留着。

只因因

给了网站http://www.ncbi.nlm.nih.gov/BLAST/查询基因序列
在这里插入图片描述
在这里插入图片描述
简写 CFTR md5加密得到flag

NCTF{254e72a3768938792446548561412d43}

炉边聚会

听说炉石传说快关服了,zys很难过,决定在最后的时间里再组一套卡组玩玩,你能找到藏在里面的flag吗?

这题一开始做的时候不知道是什么东西,后来实在没思路就看着说明,搜了搜炉石传说,发现这段字符应该就是炉石的套牌代码,一下子就觉得只要找到卡组,flag肯定就没问题了。自己还装了一个炉石,结果代码复制进去完全没反应,然后搜的时候弹出了很多卡组代码的组成原理,于是就开始漫长的学习卡组代码的组成原理。

参考:炉石传说卡组代码是什么原理?代码是如何对应卡牌的?

<?php
function read_varint(&$data) {
    $shift = 0;
    $result = 0;
    do {
        $c = array_shift($data);
        $result |= ($c & 0x7f) << $shift;
        $shift += 7;
    }
    while ($c & 0x80);
    return $result;
}

function parse_deck($data) {
    $reserve = read_varint($data);
    if ($reserve != 0) {
        printf("Invalid deckstring");
        die;
    }
    $version = read_varint($data);
    if ($version != 1) {
        printf("Unsupported deckstring version %s", $version);
        die;
    }
    $format = read_varint($data);
    $heroes = [];
    $num_heroes = read_varint($data);
    for ($i = 0; $i < $num_heroes; $i++) {
        $heroes[] = read_varint($data);
    }
    $cards = [];
    $num_cards_x1 = read_varint($data);
    for ($i = 0; $i < $num_cards_x1; $i++) {
        $card_id = read_varint($data);
        $cards[] = [$card_id, 1];
    }
    $num_cards_x2 = read_varint($data);
    for ($i = 0; $i < $num_cards_x2; $i++) {
        $card_id = read_varint($data);
        $cards[] = [$card_id, 2];
    }
    $num_cards_xn = read_varint($data);
    for ($i = 0; $i < $num_cards_xn; $i++) {
        $card_id = read_varint($data);
        $count = read_varint($data);
        $cards[] = [$card_id, $count];
    }
    return [$cards, $heroes, $format];
}

$deckstring = "AAEDAZoFKIwGngXIBrwFzgnQBfIHygf0CIgJkAi+BogJ1gjMCPIHtgeeBeAD6AfyB7YHvgbgA+AD4AO2B7wFkgnMCMwI+ga2B/QImgi6BJAIiAn2BOIJAAA=";
#这是一个非常有趣的萨满卡组
$binary = base64_decode($deckstring);
$hex = bin2hex($binary);
$arr = str_split($hex, 2);
$arr = array_map("hexdec", $arr);
$arr = parse_deck($arr);
var_dump($arr);

执行结果

array(3) {
  [0] =>
  array(40) {
    [0] =>
    array(2) {
      [0] =>
      int(780)
      [1] =>
      int(1)
    }
    [1] =>
    array(2) {
      [0] =>
      int(670)
      [1] =>
      int(1)
    }
    [2] =>
    array(2) {
      [0] =>
      int(840)
      [1] =>
      int(1)
    }
    [3] =>
    array(2) {
      [0] =>
      int(700)
      [1] =>
      int(1)
    }
    [4] =>
    array(2) {
      [0] =>
      int(1230)
      [1] =>
      int(1)
    }
    [5] =>
    array(2) {
      [0] =>
      int(720)
      [1] =>
      int(1)
    }
    [6] =>
    array(2) {
      [0] =>
      int(1010)
      [1] =>
      int(1)
    }
    [7] =>
    array(2) {
      [0] =>
      int(970)
      [1] =>
      int(1)
    }
    [8] =>
    array(2) {
      [0] =>
      int(1140)
      [1] =>
      int(1)
    }
    [9] =>
    array(2) {
      [0] =>
      int(1160)
      [1] =>
      int(1)
    }
    [10] =>
    array(2) {
      [0] =>
      int(1040)
      [1] =>
      int(1)
    }
    [11] =>
    array(2) {
      [0] =>
      int(830)
      [1] =>
      int(1)
    }
    [12] =>
    array(2) {
      [0] =>
      int(1160)
      [1] =>
      int(1)
    }
    [13] =>
    array(2) {
      [0] =>
      int(1110)
      [1] =>
      int(1)
    }
    [14] =>
    array(2) {
      [0] =>
      int(1100)
      [1] =>
      int(1)
    }
    [15] =>
    array(2) {
      [0] =>
      int(1010)
      [1] =>
      int(1)
    }
    [16] =>
    array(2) {
      [0] =>
      int(950)
      [1] =>
      int(1)
    }
    [17] =>
    array(2) {
      [0] =>
      int(670)
      [1] =>
      int(1)
    }
    [18] =>
    array(2) {
      [0] =>
      int(480)
      [1] =>
      int(1)
    }
    [19] =>
    array(2) {
      [0] =>
      int(1000)
      [1] =>
      int(1)
    }
    [20] =>
    array(2) {
      [0] =>
      int(1010)
      [1] =>
      int(1)
    }
    [21] =>
    array(2) {
      [0] =>
      int(950)
      [1] =>
      int(1)
    }
    [22] =>
    array(2) {
      [0] =>
      int(830)
      [1] =>
      int(1)
    }
    [23] =>
    array(2) {
      [0] =>
      int(480)
      [1] =>
      int(1)
    }
    [24] =>
    array(2) {
      [0] =>
      int(480)
      [1] =>
      int(1)
    }
    [25] =>
    array(2) {
      [0] =>
      int(480)
      [1] =>
      int(1)
    }
    [26] =>
    array(2) {
      [0] =>
      int(950)
      [1] =>
      int(1)
    }
    [27] =>
    array(2) {
      [0] =>
      int(700)
      [1] =>
      int(1)
    }
    [28] =>
    array(2) {
      [0] =>
      int(1170)
      [1] =>
      int(1)
    }
    [29] =>
    array(2) {
      [0] =>
      int(1100)
      [1] =>
      int(1)
    }
    [30] =>
    array(2) {
      [0] =>
      int(1100)
      [1] =>
      int(1)
    }
    [31] =>
    array(2) {
      [0] =>
      int(890)
      [1] =>
      int(1)
    }
    [32] =>
    array(2) {
      [0] =>
      int(950)
      [1] =>
      int(1)
    }
    [33] =>
    array(2) {
      [0] =>
      int(1140)
      [1] =>
      int(1)
    }
    [34] =>
    array(2) {
      [0] =>
      int(1050)
      [1] =>
      int(1)
    }
    [35] =>
    array(2) {
      [0] =>
      int(570)
      [1] =>
      int(1)
    }
    [36] =>
    array(2) {
      [0] =>
      int(1040)
      [1] =>
      int(1)
    }
    [37] =>
    array(2) {
      [0] =>
      int(1160)
      [1] =>
      int(1)
    }
    [38] =>
    array(2) {
      [0] =>
      int(630)
      [1] =>
      int(1)
    }
    [39] =>
    array(2) {
      [0] =>
      int(1250)
      [1] =>
      int(1)
    }
  }
  [1] =>
  array(1) {
    [0] =>
    int(666)
  }
  [2] =>
  int(3)
}

其它wp脚本
这个要先转换为8位的二进制,根据卡组编码规则,把代码转为十六进制,再转二进制

fflag=['10001100','00000110','10011110','00000101','11001000','00000110','10111100','00000101','11001110','00001001','11010000','00000101','11110010','00000111','11001010','00000111','11110100','00001000','10001000','00001001','10010000','00001000','10111110','00000110','10001000','00001001','11010110','00001000','11001100','00001000','11110010','00000111','10110110','00000111','10011110','00000101','11100000','00000011','11101000','00000111','11110010','00000111','10110110','00000111','10111110','00000110','11100000','00000011','11100000','00000011','11100000','00000011','10110110','00000111','10111100','00000101','10010010','00001001','11001100','00001000','11001100','00001000','11111010','00000110','10110110','00000111','11110100','00001000','10011010','00001000','10111010','00000100','10010000','00001000','10001000','00001001','11110110','00000100','11100010','00001001','00000000','00000000']
for i in range(40):
    flag=fflag[2*i+1]+fflag[2*i][1:-1]+fflag[2*i][-1]
    fla=int(flag,2)
    fl=fla//10
    print(chr(fl),end='')

脚本三;可以直接出

from hearthstone.deckstrings import Deck

deck = Deck.from_deckstring('AAEDAZoFKIwGngXIBrwFzgnQBfIHygf0CIgJkAi+BogJ1gjMCPIHtgeeBeAD6AfyB7YHvgbgA+AD4AO2B7wFkgnMCMwI+ga2B/QImgi6BJAIiAn2BOIJAAA=')

for card in deck.cards:
    flag_part = int(card[0] / 10)
    print(chr(flag_part), end='')
NCTF{HearthStone_C0de_S000_FunnY_ri9ht?}

zystego

可以分离出一个zip,爆破密码
在这里插入图片描述
flag.txt是假的
在这里插入图片描述somethin里有一堆不认识的东西,开头可以拿去搜一下,发现是PGP的私钥,然后这里就不会了,一直学PGP没搞懂,到底加密后的是什么,就给我个密钥怎么解。现在看了wp才发现,fd.png里还有东西。
fd.png右边一列奇怪的东西
请添加图片描述

提取RGB
看wp,可以用lsb找,但我一直找不出来,只能用脚本(但别说脚本真的香)

from PIL import Image

im = Image.open('fd.png')
pix = im.load()
width = im.size[0]
height = im.size[1]
for x in range(height):
    for y in range(width-3,width):
        r,g,b = pix[y,x]
        print(r,g,b)

在这里插入图片描述

from PIL import Image

im = Image.open('fd.png')
pix = im.load()
width = im.size[0]
height = im.size[1]
for x in range(height):
    for y in range(width-3,width):
        r, g, b = pix[y,x]
        #print(r,g,b)
        if r%10 == 0:
            print(0,end='')
        else:
            print(1,end='')
        if g%10 == 0:
            print(0,end='')
        else:
            print(1,end='')
        if b%10 == 0:
            print(0,end='')
        else:
            print(1,end='')

在这里插入图片描述到这里我也不认识了(要学的东西还多)
一个dct算法,末尾是key

import numpy as np
import cv2

丁真 = np.float32(cv2.imread(r"fd.png",1))

for i in range(64):
    for j in range(64):
        for 芝士 in range(3):
            小马珍珠 = 丁真[:, :, 芝士]
            雪豹 = cv2.dct(小马珍珠[8*i:8*i+8, 8*j:8*j+8])
            print(雪豹[7,7])
import numpy as np
import cv2

丁真 = np.float32(cv2.imread(r"fd.png",1))

for i in range(64):
    for j in range(64):
        for 芝士 in range(3):
            小马珍珠 = 丁真[:, :, 芝士]
            雪豹 = cv2.dct(小马珍珠[8*i:8*i+8, 8*j:8*j+8])
            # print(雪豹[7,7])
            if(雪豹[7,7] > 10):
                print(1,end='')
            elif(雪豹[7,7] < -10):
                print(0,end='')

得到一个zip,即为加密文件
在这里插入图片描述
在这里插入图片描述

key:%$#%$#jhgasdfg76342t

NCTF{zys_1s_s0_V3g3T@13lE_qwq}

qrssssssss

有什么东西掩盖住了zys的双眼,好像在给他指明方向!(flag括号内的内容只有26位

这题,512个二维码,一开始以为会组成什么东西,扫完发现NCTF{}有这东西,那一想,二维码按顺序扫描,flag不就出来了。然后发现每个二维码名字是时间,于是想到会不会按时间顺序就能扫出来了。

这个脚本才让我明白这题的原理,时间竟然是非预期

from PIL import Image
import pyzbar.pyzbar as pyzbar
import os

def qrcode_parse_content(img_path):
    '''
    单张图片的二维码解析
    '''
    img = Image.open(img_path)

    #使用pyzbar解析二维码图片内容
    barcodes = pyzbar.decode(img)

    #打印解析结果,从结果上可以看出,data是识别到的二维码内容,rect是二维码所在的位置
    # print(barcodes)
    # [Decoded(data=b'http://www.h3blog.com', type='QRCODE', rect=Rect(left=7, top=7, width=244, height=244), polygon=[Point(x=7, y=7), Point(x=7, y=251), Point(x=251, y=251), Point(x=251, y=7)])]

    result = []
    for barcode in barcodes:
        barcode_content = barcode.data.decode('utf-8')
        result.append(barcode_content)

    return result

def load_imgs(folder):
    '''
    加载文件夹下的图片
    '''
    imgs = []
    for img_path in os.listdir(folder):
        ext = os.path.splitext(img_path)
        if len(ext) > 1 and is_img(ext[1]):
            imgs.append(img_path)

    return imgs

def is_img(ext):
    '''
    判断文件后缀是否是图片
    '''
    ext = ext.lower()
    if ext == '.jpg':
        return True
    elif ext == '.png':
        return True
    elif ext == '.jpeg':
        return True
    elif ext == '.bmp':
        return True
    else:
        return False

if __name__ == "__main__":

    imgs = load_imgs('./') # 打开图片文件夹,我这里是当前程序运行目录
    contents = []
    # for img in imgs:
    #     contents.extend(qrcode_parse_content(img))
    #     print( img)
    # file = './result.txt' # 写入文件路径,我这里程序当前运行目录下的result.txt
    # with open(file,'w',encoding='utf-8') as f:
    #     for c in contents:
    #         f.write(c + '\n')
    for img in imgs:
        print(qrcode_parse_content(img)[0],end='')
e1b19411bCT3ef91e-T6--5115-b-eNe5-01e-1-0}1a15-0e91e50N15-eTa3-0e}8bC16ee11feeeeb7{ae1eeNbC7Ta1T-5bFb--398a515-NbTfbb-8-7ef-}0C-Te4eF501f{6a51e4be--5-Fb0}Fb-5{b97ef8a-{fa11bC9fee-3-e9N{1-51T1NN01C41883{577-1e-T1603{C{-17-NNeC0f-0C39711514{9117F--6-F-e05a7517C3b4-F{F71f}-1fe70-34-{7805C}b{bCf1f-aT{e3aFe-f-0bT6C17000N78e-76}af7-}4N-907}03187b113T9eaeF--13ebeN71b-C9Te1eF-680-468675F17410674N910F51b1511--80FF565165-19}beT}N17N-1758e-}1a8-4C-0057e-5b7b0}5}{7eaN-{-b}36b}7eb0-606{15b4b01971T-59388-Te351eFC044417af

在这里插入图片描述二维码纠错级别LMQH
参考文章:如何一眼看出二维码的纠错等级
另一种方法

脚本输出二维码内容和修改时间

# coding: UTF-8
from PIL import Image
import pyzbar.pyzbar as pyzbar
import os

def qrcode_parse_content(img_path):
    '''
    单张图⽚的⼆维码解析
    '''
    img = Image.open(img_path)
    #使⽤pyzbar解析⼆维码图⽚内容
    barcodes = pyzbar.decode(img)
    #打印解析结果,从结果上可以看出,data是识别到的⼆维码内容,rect是⼆维码所在的位置
    # print(barcodes)
    # [Decoded(data=b'http://www.h3blog.com', type='QRCODE', rect=Rect(left=7, t
    result = []
    for barcode in barcodes:
        barcode_content = barcode.data.decode('utf-8')
        result.append(barcode_content)
    return result

def load_imgs(folder):
    '''
    加载⽂件夹下的图⽚
    '''
    imgs = []
    for img_path in os.listdir(folder):
        ext = os.path.splitext(img_path)
        if len(ext) > 1 and is_img(ext[1]):
            imgs.append(img_path)
    return imgs

def is_img(ext):
    '''
    判断⽂件后缀是否是图⽚
    '''
    ext = ext.lower()
    if ext == '.jpg':
        return True
    elif ext == '.png':
        return True
    elif ext == '.jpeg':
        return True
    elif ext == '.bmp':
        return True
    else:
        return False

if __name__ == "__main__":
    # path = "C:/Users/KG/Desktop/1/"
    path = 'C://Users/LENOVO/Desktop/NCTF2022/qrssssssss/qrssssssss/'
    imgs = load_imgs(path)  # 打开图⽚⽂件夹,我这⾥是当前程序运⾏⽬录
    contents = []
    for img in imgs:
        print(img, end='\t')
        old_name = img[:15]
        # print(old_name)
        print(qrcode_parse_content(path + img)[0], end='\t')
        print(os.path.getatime(path + img), end='\t')
        print(os.path.getctime(path + img), end='\t')
        print(os.path.getmtime(path + img))
    # new_name = old_name+'_'+qrcode_parse_content(path+img)[0]+'.png'
    # print(old_name+'_'+new_name+'.png')
    # print(qrcode_parse_content(path+img))
    # os.rename(path+img, path+new_name)
    # contents.extend(qrcode_parse_content(path+img))

脚本输出二维码的纠错级别

from PIL import Image
import pyzbar.pyzbar as pyzbar
import os

def qrcode_parse_content(img_path):
    '''
    单张图⽚的⼆维码解析
    '''
    img = Image.open(img_path)
    #使⽤pyzbar解析⼆维码图⽚内容
    barcodes = pyzbar.decode(img)
    #打印解析结果,从结果上可以看出,data是识别到的⼆维码内容,rect是⼆维码所在的位置
    # print(barcodes)
    # [Decoded(data=b'http://www.h3blog.com', type='QRCODE', rect=Rect(left=7, t
    result = []
    for barcode in barcodes:
        barcode_content = barcode.data.decode('utf-8')
        result.append(barcode_content)
    return result

def load_imgs(folder):
    '''
    加载⽂件夹下的图⽚
    '''
    imgs = []
    for img_path in os.listdir(folder):
        ext = os.path.splitext(img_path)
        if len(ext) > 1 and is_img(ext[1]):
            imgs.append(img_path)

    return imgs

def is_img(ext):
    '''
    判断文件后缀是否是图片
    '''
    ext = ext.lower()
    if ext == '.jpg':
        return True
    elif ext == '.png':
        return True
    elif ext == '.jpeg':
        return True
    elif ext == '.bmp':
        return True
    else:
        return False

def get_level(i):
    img = Image.open(i)
    if img.load()[10, 170] == 0 and img.load()[30, 170] == 0:
        return(i, 'L')
    if img.load()[10, 170] == 0 and img.load()[30, 170] == 255:
        return(i, 'M')
    if img.load()[10, 170] == 255 and img.load()[30, 170] == 0:
        return(i, 'Q')
    if img.load()[10, 170] == 255 and img.load()[30, 170] == 255:
        return(i, 'H')

if __name__ == "__main__":
    path = "C://Users/LENOVO/Desktop/NCTF2022/qrssssssss/qrssssssss/"
    # path = 'C://Users/KG/Downloads/qrssssssss/'
    imgs = load_imgs(path) # 打开图⽚⽂件夹,我这⾥是当前程序运⾏⽬录
    contents = []

    for img in imgs:
        old_name = img[:15]
        print(old_name,end='\t')
        print(qrcode_parse_content(path+img)[0],end='\t')
        print(get_level(path+img)[1],end='\t')
        print(os.path.getatime(path+img),end='\t')
        print(os.path.getctime(path+img),end='\t')
        print(os.path.getmtime(path+img))
        # new_name = old_name+'_'+qrcode_parse_content(path+img)[0]+'.png'
        # print(old_name+'_'+new_name+'.png')
        # print(qrcode_parse_content(path+img))
        # os.rename(path+img, path+new_name)

按纠错顺序排序即可得到flag

NCTF{737150-eeb-465-e91-110a8fb}

qrssssssss_revenge

LMQH

这道就是纯LMQH来排序了,没有非预期

NCTF{62130783efd44b3692b4ddbecf}

参考:

南邮-NCTF2022 WRITE UP

Scr1w战队wp(比赛群里师傅发的)

如何一眼看出二维码的纠错等级

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

slawgut

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值