[WP]36D杯
很多图片
写脚本全部down下来
#coding:utf-8 import requests a="0123456789abcdefgh" for i in a: for j in a: img_url = "https://ctfshow.gitee.io/subject_puzzle/data/"+i+j+".jpg" img = requests.get(img_url) f = open(i+j+'.jpg','ab') #存储图片,多媒体文件需要参数b(二进制文件) f.write(img.content) #多媒体存储content f.close()
js里有个check函数
得知是将排列后的图片名按顺序组合起来,判断sha256是否正确 如果正确则flag就是原字符串的md5
原图拿过来,发现拆分的小图和原图的比例不一样,通过计算得知每张小图对应原图的像素约为128*95
小图缩放脚本
import sys import os from PIL import Image jpg_path=sys.path[0]+'/' jpg_names=[name for name in os.listdir(jpg_path)] jpg_save_path=sys.path[0]+'/img/' for i in jpg_names: image = Image.open(jpg_path+i) image.thumbnail((128,95)) image.save(jpg_save_path+i[:-4]+".png") print(i)
原图位置对照脚本
# -*-encoding:utf-8-*- import pytesseract from PIL import Image from PIL import ImageFilter from PIL import ImageFont from PIL import ImageDraw import numpy as np from PIL import Image import os import cv2 def main(): # 使用模板匹配在图像中寻找物体 # OpenCV函数:cv2.matchTemplate(), cv2.minMaxLoc() # 模板匹配就是用来在大图中找小图,也就是说在一副图像中寻找另外一张模板图像的位置 # =================================匹配多个物体,模板匹配 # 1.读入原图和模板 img_rgb = cv2.imread('origin_img.jpg') img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY) jpg_path="C:\\Users\\80597\\Desktop\\36D\\pintu\\img"+'/' jpg_names=[name for name in os.listdir(jpg_path)] for i in jpg_names: #print(i) template = cv2.imread("C:\\Users\\80597\\Desktop\\36D\\pintu\\img"+'/'+i, 0) h, w = template.shape[:2] # 2.标准相关模板匹配 res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED) threshold = 0.8 # 3.这边是Python/Numpy的知识,后面解释 loc = np.where(res >= threshold) # 匹配程度大于%80的坐标y,x,loc是先y坐标再x坐标 #print(loc) print(i[:-4],round((loc[0][1]-228)/95),round((loc[1][1]-130)/128)) for pt in zip(*loc[::-1]): # *号表示可选参数,,所以用loc[::-1]翻转一下,然后再用zip函数拼接在一起。 right_bottom = (pt[0] + w, pt[1] + h) cv2.rectangle(img_rgb, pt, right_bottom, (0, 0, 255), 2) #cv2.imshow('img_rgb', img_rgb) #cv2.waitKey(0) if __name__ == '__main__': main()
复制到excel排个序
连起来提交用js取sha256是正确的.
这里最开始用了CMD5来取sha256,不知道怎么回事一直不对,最后在浏览器取了一次发现之前就是对的
取个md5套个马甲提交
附带一个拼图验证易语言脚本(由于之前一直以为py脚本识别错了,又拿识别结果拼了一下)
.版本 2 .程序集 窗口程序集_启动窗口 .子程序 _按钮1_被单击 .局部变量 文件号, 整数型 .局部变量 文件名, 文本型 .局部变量 i, 整数型 .局部变量 j, 整数型 .局部变量 tu, 整数型 文件号 = 打开文件 (“C:\Users\80597\Desktop\rank.txt”, , ) .计次循环首 (13, i) .计次循环首 (23, j) 文件名 = 读入一行 (文件号) 输出调试文本 (文件名) tu = 载入图片 (“C:\Users\80597\Desktop\36D\pintu\img\” + 文件名 + “.png”) 画板1.画图片 (tu, j × 64, i × 48, 64, 48, ) .计次循环尾 () .计次循环尾 ()
stegsolver按几下方向键就有了
流量分析,首先可以分离出一个有密码的压缩包
追踪一下http流,得知存放密码的变量为这个teqtbz,猜测压缩包密码也是这个
追踪TCP流找到密码
先rot47 得到(hou_mian_shi_flag)^b^%&(^@^f^!&@^$%f^%^e^#
符号表示键盘上对应符号键的数字部分 abcde则照抄 得到十六进制解密
#include<stdio.h> #include<string.h> int main(){ char a[]={102,109,99,98,127,58,85,106,57,82,122,55,81,19,51,35,67,70,41,61,41,32,127,28,38,77,49,20,80,94}; for(int i = 0;i<strlen(a);i++){ printf("%c",i^(i+(a[i]^i))); } }
IDA查看拿到key:wangzherongyao
OD调试拿flag
nc连接直接执行shell了
解密得到flag
运行提示缺少DLLFlag.dll
构造一个
塞点看起来有可能用到的函数(易语言是世界上最好的语言)
再运行提示找不到FlagIsNotHerePlzRemoveMe的入口点
再塞个函数进去
.版本 2 .程序集 程序集1 .子程序 _启动子程序, 整数型, , 请在本子程序中放置动态链接库初始化代码 _临时子程序 () ' 在初始化代码执行完毕后调用测试代码 返回 (0) ' 返回值被忽略。 .子程序 _临时子程序 ' 本名称子程序用作测试程序用,仅在开发及调试环境中有效,编译发布程序前将被系统自动清空,请将所有用作测试的临时代码放在本子程序中。 ***注意不要修改本子程序的名称、参数及返回值类型。 .子程序 DLLFlag, 整数型, 公开 返回 (0) .子程序 Flag, 整数型, 公开 返回 (0) .子程序 flag, 整数型, 公开 返回 (0) .子程序 dllflag, 整数型, 公开 返回 (0) .子程序 FlagIsNotHerePlzRemoveMe, 整数型, 公开 返回 (0)
看flag应该我这是非预期解法,正解应该是把程序对dll的依赖都去掉的
已知key,提取n和e
#coding:utf-8 from Crypto.PublicKey import RSA pub = RSA.importKey(open('public.key').read()) n = long(pub.n) e = long(pub.e) print n print e
通过n分解出pq
密文解密
#coding:utf-8 import gmpy2 import rsa e=65537 p=gmpy2.mpz(302825536744096741518546212761194311477) q=gmpy2.mpz(325045504186436346209877301320131277983) c=gmpy2.mpz(0x0F04B3B67EF230F80BB518D26DED38AF84B6C8D87BA80C09EBF1D865123082FA) n=p*q d = int(gmpy2.invert(e, (p-1)*(q-1))) m = pow(c, d, n) print len(str(n)) print gmpy2.iroot print("十进制:\n%s"%m) m_hex = hex(m)[2:] print("十六进制:\n%s"%(m_hex,))
三段密文分别解密后提取16转ascii
三消题,大概有这么几种一步消除方法
对着写脚本 1/2w比较好跑,到5w确实需要运气,不知道什么时候就无解分数清零了,一共大概跑了五六次
from pwn import * import random p=remote("124.156.121.112",28063) p.recvuntil("continue") p.sendline("") dd=['W','A','S','D'] matrix = [['a','a','a','a','a','a','a','a'], ['a','a','a','a','a','a','a','a'], ['a','a','a','a','a','a','a','a'],['a','a','a','a','a','a','a','a'],['a','a','a','a','a','a','a','a'],['a','a','a','a','a','a','a','a'],['a','a','a','a','a','a','a','a'],['a','a','a','a','a','a','a','a']] def getchange(): for i in range(7): for j in range(6): if(matrix[i+1][j]==matrix[i][j+1]==matrix[i][j+2]): return(str(j)+str(i+1)+'W') if(matrix[i][j]==matrix[i][j+1]==matrix[i+1][j+2]): return(str(j+2)+str(i+1)+'W') if(matrix[i][j]==matrix[i][j+2]==matrix[i+1][j+1]): return(str(j+1)+str(i+1)+'W') for i in range(7): for j in range(6): if(matrix[i][j]==matrix[i+1][j+1]==matrix[i+1][j+2]): return(str(j)+str(i)+'S') if(matrix[i+1][j]==matrix[i+1][j+1]==matrix[i][j+2]): return(str(j+2)+str(i)+'S') if(matrix[i+1][j]==matrix[i+1][j+2]==matrix[i][j+1]): return(str(j+1)+str(i)+'S') for j in range(7): for i in range(6): if(matrix[i][j+1]==matrix[i+1][j]==matrix[i+2][j]): return(str(j+1)+str(i)+'A') if(matrix[i][j]==matrix[i+1][j]==matrix[i+2][j+1]): return(str(j+1)+str(i+2)+'A') if(matrix[i][j]==matrix[i+2][j]==matrix[i+1][j+1]): return(str(j+1)+str(i+1)+'A') for j in range(7): for i in range(6): if(matrix[i][j]==matrix[i+1][j+1]==matrix[i+2][j+1]): return(str(j)+str(i)+'D') if(matrix[i][j+1]==matrix[i+1][j+1]==matrix[i+2][j]): return(str(j)+str(i+2)+'D') if(matrix[i][j+1]==matrix[i+1][j]==matrix[i+2][j+1]): return(str(j)+str(i+1)+'D') for i in range(8): for j in range(5): if(matrix[i][j]==matrix[i][j+1]==matrix[i][j+3]): return(str(j+3)+str(i)+'A') if(matrix[i][j]==matrix[i][j+2]==matrix[i][j+3]): return(str(j)+str(i)+'D') for j in range(8): for i in range(5): if(matrix[i][j]==matrix[i+1][j]==matrix[i+3][j]): return(str(j)+str(i+3)+'W') if(matrix[i][j]==matrix[i+2][j]==matrix[i+3][j]): return(str(j)+str(i)+'S') return(str(random.randint(0,7))+str(random.randint(0,7))+dd[random.randint(0,3)]) score=0 while(score<50000): p.recvuntil("Score:") score=int(p.recv(8)) print(score) p.recvuntil('7') for i in range(8): line=str(i) p.recvuntil(line) for j in range(8): matrix[i][j]=p.recv(1) for i in range(7): print(matrix[i]) a=getchange() p.sendline(a) print(a) p.interactive()
师傅给了两个要用的密码,使用第一个密码加压题目文件,得到十六进制字符组成的文本
把文本转换成二进制文件,首先把'0xa'替换成'0x0a';'0x'替换成'';' '替换成''
大文本文件推荐使用EmEditor做处理(也没几个软件打得开三百兆的文本)
替换完后hxd创建一个文件将十六进制复制进去,得到一个由base64字符组成的文件
base64解码
# -*- coding: utf-8 -*- import os import base64 import sys #strs = sys.argv[1] # 读取命令行中输入的参数,即base64字符串 f=open('C:\\Users\\80597\\Desktop\\36D\\virt\\flag_base64','r') strs=f.read() f.close() img = base64.b64decode(strs) #img=base64.b16encode(img) #print(img) file = open('C:\\Users\\80597\\Desktop\\36D\\virt\\15555.zip','wb') file.write(img) file.close()
得到一个带密码的压缩文件 使用给的第二个密码解密得到.qcow2镜像文件
用7z粗略地看了一下,发现一个flag文件
提出来是一串十进制数
直觉告诉我flag和这个有关,当ascii码转一下试试
不可读
凭着多年逆向签到题的宝贵经验,尝试用前几组数字和后几组数字分别和'flag''galf'做异或,发现了神奇的东西
19,18,17,16...排列
写了脚本直接拿到了倒着的flag
感觉这是非预期解法,和师傅交流了一下
...
base64解密两次后拿到32个字符一行的密码
一开始一直当作加密的文件在搞
最后cmd5解密得到flag