2022年江西省大学生信息安全技术大赛初赛writeup——re、misc、crypto方向

admin 2022年10月16日23:08:28评论281 views字数 10644阅读35分28秒阅读模式

关注公众号,后台回复“2022年江西省大学生信息安全技术大赛初赛附件”获取附件。writeup为火炬木攻防实验室复现。

Misc

av番号?

分离png得到压缩包

2022年江西省大学生信息安全技术大赛初赛writeup——re、misc、crypto方向

密码即为av号所对应的bv号,打开即可获得flag

2022年江西省大学生信息安全技术大赛初赛writeup——re、misc、crypto方向

DASCTF{2cf74144f7a6753b8ec5ef1a17bd6943}

b64

文件尾有rar,winhex手动分离另存为1.rar

2022年江西省大学生信息安全技术大赛初赛writeup——re、misc、crypto方向

打开rar提示文件损坏,尝试手动修复

将7A修改为74后有一个CMT文件

2022年江西省大学生信息安全技术大赛初赛writeup——re、misc、crypto方向

内部数据为375c24f24

2022年江西省大学生信息安全技术大赛初赛writeup——re、misc、crypto方向

WinRAR打开,直接拖出来就可以,会提示输入密码,直接点确定即可

2022年江西省大学生信息安全技术大赛初赛writeup——re、misc、crypto方向

获得flag.png

2022年江西省大学生信息安全技术大赛初赛writeup——re、misc、crypto方向
Mc25LaMdwVfSrAcTi5hUjdjZigLVtdfWj50Btbvat5YTtJjZiV7JXL==

直接使用常见base64表都无法解码,所以考虑还有密码表未找到

这个时候发现b64.png是有lsb隐写的

2022年江西省大学生信息安全技术大赛初赛writeup——re、misc、crypto方向

结合上面获取的375c24f24作为密钥,进行lsb隐写解密,获得密码表

2022年江西省大学生信息安全技术大赛初赛writeup——re、misc、crypto方向

换表获取flag

2022年江西省大学生信息安全技术大赛初赛writeup——re、misc、crypto方向

Reverse

just try

日常查壳

2022年江西省大学生信息安全技术大赛初赛writeup——re、misc、crypto方向

ida32打开抓住main函数,看到一串类似于base的加密

下面整体分析一下,加密完成对应汇编2022年江西省大学生信息安全技术大赛初赛writeup——re、misc、crypto方向

动调一下了解加密的过程

2022年江西省大学生信息安全技术大赛初赛writeup——re、misc、crypto方向

输三出四abc->d7Jo

类base加密,表应该是

 pc$LEQz=`J&x}Z1H[_#WY?7(d+beh9Rg%U.omaADIn/^r2qj"X8*SPiVT~,!@0lO

分析加密思路,发现和b64很相似基本判断就可以看成一个变表的base

刚好表也是64位,映证我的想法

尝试写写解密脚本

import base64
xx = "9zUnhP0nhP0U(i+Ubi?g+AXU+P0Vbz?8+?0nhP0Sbz?g9=JP+W@="
string1 = "pc$LEQz=`J&x}Z1H[_#WY?7(d+beh9Rg%U.omaADIn/^r2qj"X8*SPiVT~,!@0lO"
string2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
print(base64.b64decode(xx.translate(str.maketrans(string1, string2))))

2022年江西省大学生信息安全技术大赛初赛writeup——re、misc、crypto方向

发现得到的结果并不正确,回头继续看

2022年江西省大学生信息安全技术大赛初赛writeup——re、misc、crypto方向

找到有两个地方引用了DASCTF{}输出flag

2022年江西省大学生信息安全技术大赛初赛writeup——re、misc、crypto方向

第一个也就是对比9zUnhP0nhP0U(i+Ubi?g+AXU+P0Vbz?8+?0nhP0Sbz?g9=JP+W@=

现在找第二个,根据ida中的地址将断点下在这里动调,找到第二个加密字符串的储存位置对应的字符串

2022年江西省大学生信息安全技术大赛初赛writeup——re、misc、crypto方向

2022年江西省大学生信息安全技术大赛初赛writeup——re、misc、crypto方向

追踪到[ebp-54]0xD9F804的位置

找到加密之后的第二个字符串:bDYP9Q0S}Vag}(_gZz~m(Vm"9?0V}7Xr(ih*9Q0Ybz?g+AXp+8E=

2022年江西省大学生信息安全技术大赛初赛writeup——re、misc、crypto方向

出flag:DASCTF{ju5t_t3y_1t_4nd_y0u_w1ll_g3t_The_fl@g!}

Crypto

childRSA

题目给了两个hint,一个t,三个式子的关系式需要注意,除此之外没有给别的条件,要利用三个式子之间的关系将n给分解,从而解得RSA问题。

移位运算需要格外注意数据的大小,hint2为325位,即p+q有1025位

2022年江西省大学生信息安全技术大赛初赛writeup——re、misc、crypto方向

可以通过hint1求出中间未知的300位,coppersmith攻击可以得解,需要注意的是参数epsilon需要调解。

#sage
PR.<x> = PolynomialRing(Zmod(n))
f = (hint2 * 2 ** 300 + x) ** 5 - hint1
f = f.monic()
root = f.small_roots(X=2^300,epsilon=0.05)
print(root)
#[900264792430764766810468133825778807801191920823522836863083047162892866646875705320428414]

这样就得到了中间300位数据,也就得到了完整的t,t为p+q的高625位。尝试将t补齐末尾的400位后,将t当作p+q进行解方程求解p和q,得到的结果高位绝大部分(约625位)都是p的真实值,即又是一次coppersmith攻击。

本地调试代码为

from Crypto.Util.number import *
import gmpy2
p = getPrime(1024)
q = getPrime(1024)
n = p * q
print(bin(p))
print(bin(q))
t = (p + q) >> 400
tmp = t << 400
delta = (-tmp) ** 2 - 4 * n
root = (tmp + gmpy2.iroot(delta,2)[0]) // 2
print(bin(root))
print(bin((root >> 410) << 410))

观察真实的p和q的值,与用高位p+q计算出的p和q对比,发现高位约410左右的值均为真实值。

最终完整的exp为

#sage
from Crypto.Util.number import *
import gmpy2
e = 0x10001
hint1 = 6964268498224091442825901686661237530522347823219684563953066748773962088742241306677313317319854958214809420491702826564173355938490895331198923527667364391468907737301225088055694814054437257546623622938612408110705668176565380596339718060188913772054934639716087768201377510580527776620973849589493097834538277938095415499237738389824293807732943558864605374620352812654675340721179976350321686554346480366405041985305950214160057477895135264060509738709041302441896671041092913276009633345558000228385343666906746902900413558103089531391702625462756747693602826394235998376415996614904736368860948851904114759520
hint2 = 35165031790811266789276297244077421419318407075263158049499021955914590950991343652276232777908755
c = 1194117711433011441060134674606098070381155137570132814645921839615957597835342364752690350397111039680829661168950994677242133003831857753717267765730709950962838353493193313333861519610959115846772660808231021695226017063586411911884012906630417263646774337811587546018982857308444743074540232702175124483283963022003128128895028486075083457146101759085577311851691019744921491271824543561105936792223059552432601797275680969934801073929816816591461641917010862943585908913395097700239584604202024790346377492049803175414595521867623349879553627712654215740750111307350401014702090262981840327908865144781276319568
n = 8549553129556983264608088682144271656693794050112289425675496094026434817108494235711226667779521325697862914028343058066103508338456921605474038543206958948754257875152530897451832886150364719949419136810566809716512257764229488443939365856512970801159298226321696518457404725027861542259048326408205187101646347015821199955131581632322611062812545798546366651032754969448116265458489609498024105014804973782490072390302931423444439067883414987213231822019508606373773220271568649831375769401969720741032679413016192706592762550683257986177763209776366348327296666255389811197464163893141112673359393597787787992057
PR.<x> = PolynomialRing(Zmod(n))
f = (hint2 * 2 ** 300 + x) ** 5 - hint1
f = f.monic()
root = f.small_roots(X=2^300,epsilon=0.05)
print(root)
tmp = int(root[0])
t = int(hint2 * 2 ** 300 + tmp)
assert pow(t,5,n) == hint1
tmp = t << 400
delta = (-tmp) ** 2 - 4 * n
p = (tmp + gmpy2.iroot(delta,2)[0]) // 2
bits = 410
p = int((p >> bits) << bits)
PR.<x> = PolynomialRing(Zmod(n))
f = p + x
root = f.small_roots(X=2^bits,beta=0.4)
print(root)
p += int(root[0])
assert n % p == 0
q = n // p
phi = (p - 1) * (q - 1)
d = gmpy2.invert(e,phi)
m = pow(c,d,n)
print(long_to_bytes(int(m)))
#b'DASCTF{you_s0lve_the_double_c0pper_problem!}'

easylattice2

n=40,m = 256,q = ,泄露βi的高s=8位。

首先把问题换个符号表述,βi拆成泄露的高未和未知的低位相加:

观察一下,现在未知数有是m bits,是(m−s) bits,如果可以把的未知量转换成((m−s) bits以下或者消去的话是最好的(按以前的经验,如果有未知数和模数一样大的话问题大概率不能解,不过也要看具体问题)。

以下选择消去减小未知数的规模:首先选一组定义为第0组(只是一个定义,实际选出来后换个位置也行),需要满足gcd(A0,q)=1,即模q可逆,需要可逆的原因是想把移到一边:

然后对i=1,2,...的每一组就可以代入然后消去,最终得到:

展开模数q:

简单推算一下,+大概(2m−s) bits,q是m bits,所以大概(m−s) bits,最终所有未知数都(m−s) bits。

令常数R=,接下来就是构造格L(B):

使得:

可算

算出若∥w∥≤σ(L(B))的话就是:

化简:

实际应用的时候还有一个技巧:在拆成的时候,是恒为正的,如果在中加上一个就可以为负,的位数变为(比原来小一位),这时把R设成,就会:

算出若∥w∥≤σ(L(B))的话就是:

即开始所说的关系。计算出取组就可解,当然取越多越好。

exp:

#sage
from Crypto.Util.number import *
def matrix_overview(BB):
    for ii in range(BB.dimensions()[0]):
        a = ('%02d ' % ii)
        for jj in range(BB.dimensions()[1]):
            if BB[ii, jj] == 0:
                a += ' '
            else:
                a += 'X'
            if BB.dimensions()[0] < 60:
                a += ' '
        print(a)


m = 256
s = 8
A = [845456050989193578833420497857002300409686939965308399459906534008555049068026431862705023862191385634265814930911195337136436224846697307650137017173986644833833707095656654503484256000993796921007419233493881691012114619868094560732320500509787297498763853551259223659946358406145779097129390784658894869274970575434368021782573168906924722293146445728836827840175695521606382146071377737165070690772861763843283117046959433461869560115856478336508725469857043536787174842609794289197575298561253217815952239248779913784716279384429725962764829622761591382777789741125592700340145715067712695838863315679297865421469359771214219792578631440037198211551181227287987665850215574614585547110484293917788903948436247958872074099135736597614843717743510116804529035975841097121564005524888337068660871158366982592875907457306709790495639937090537232768867012538074155889435382916759315827036672399329885014278681962932887084542613550537734877982100804926547341582146602587691102361185297077301408834169711099584944214494087042704813389915660841955092726694244287790153360326650536350442036066387738796374028749884594699683644712579249225887543077991724361112665604848469247498374079779039877909487959491708401136315883984900023830087106082111880140350563516845222048616300919360816856986713701434503153473598272875951209973467011537718441733549623635059900247499600323235228021702108569983073546983400537139209852268346086262872800056309973724641478768916165417000574359883667893599589405273462303347696610905658857136168118529986363407255898202041977802052978430817116482262944804480193262734556170211959998570441679426309626278375151698098319218635606514984143190725939514191045138343370470918412152056244753544826439613524228624069728455796264166814352560273933151913592114889255822548504838278221664465176494052041487922417522436000874970493661674126976450379891545077489397499107147684361174285765112373334272906377452323527529958885135892459310663331597275282361340183165684984577622097140892686475766252398829865053651294427099510477412334399373429337393371739360897428551080965321983114464830933751709798249340726924355079458525999418946778543247622346139286263397899992951419178195053475916568135172144122694657112490581510300343764600225228777443826390643171716867504198810024999401208075939066226299199650174232373088152191081329628494234034901633083715515933520198651338654685877138784030740465724716203856139754018741545301925742743136359127104441232992577594358117502879406491475351452285831554990385376976757282352580330659016772729736188325303860093961220099265756043996067476342007946217299704442866698623401758127641977798857113971736125468419263857787075540336458711365758576497685326065127383311053093506819164803494850764935860565527696242803546094270177195957399731112654492041096174301599193436777349826784319243378345939534738486568022924301252995070743709076133954812487027394051823868169701714096819788654835991350892017714704136475665901473847180701989592267942240926257585702892353939170592029768060112909867989273389149830947499985690619642365711664985]
B = [2311341842612521412542191451923021111424217518013476238310816422722021219722614725224124989269823221319214536]

AAA = [x for x in A]
BBB = [x for x in B]

while True:
  A = [x for x in AAA]
  B = [x for x in BBB]
  #B = [x << (m-s) for x in B]
  B = [(x << (m-s)) + (1 << (m-s-1)) for x in B]
  assert len(A) == len(B)
  q = 2^m

  n = len(A)-1

  AA = [x for x in A]
  BB = [x for x in B]
  for choice in range(n):
    A = [x for x in AA]
    B = [x for x in BB]
    if A[choice] % 2 != 1:
      continue
    A0 = A[choice]
    A0i = A0.inverse_mod(q)
    B0 = B[choice]
    del A[choice]
    del B[choice]
    assert gcd(A0, q) == 1
    Mt = matrix(ZZ, n+2)
    for i in range(n):
      Mt[i, i]  = -q
      Mt[-2, i] = A0i*A[i] % q
      Mt[-1, i] = A0i*(A[i]*B0 - A0*B[i]) % q
    Mt[-2-2] = 1
    R = 2^(m-s-1)
    Mt[-1-1] = R
    #print(det(Mt) == 0)
    #matrix_overview(Mt)

    L = Mt.BKZ()

    for l in L:
      if l[-1] == R:
        b = vector(l)

        b0 = b[-2]
        #print(b0)

        x0 = (B0+b0) * A0.inverse_mod(q) % q

        test1 = [bi >> (m-s) for bi in B] 
        test2 = [(ai*x0 % q) >> (m-s) for ai in A]

        print(long_to_bytes(x0))
        print(test1)
        print(test2)
        print()

        if test1 == test2:
          print('get: %d' % x0)
          exit(0)
#b'5f0552110ef8c3dbfb892697bf889bf6'
#[231, 134, 184, 1, 252, 141, 254, 219, 145, 192, 30, 211, 114, 242, 175, 180, 134, 76, 238, 3, 108, 164, 227, 220, 212, 197, 226, 147, 252, 241, 249, 89, 26, 98, 232, 213, 192, 145, 36]
#[231, 134, 184, 1, 252, 141, 254, 219, 145, 192, 30, 211, 114, 242, 175, 180, 134, 76, 238, 3, 108, 164, 227, 220, 212, 197, 226, 147, 252, 241, 249, 89, 26, 98, 232, 213, 192, 145, 36]

#get: 24153132093824532405578251214404236997470757161095572611640663666873489057334


原文始发于微信公众号(火炬木攻防实验室):2022年江西省大学生信息安全技术大赛初赛writeup——re、misc、crypto方向

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年10月16日23:08:28
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   2022年江西省大学生信息安全技术大赛初赛writeup——re、misc、crypto方向https://cn-sec.com/archives/1352893.html

发表评论

匿名网友 填写信息