Teaser CONFidence CTF 2019

1.count me in

下载程序文件阅读,发现这是一个aes ctr加密算法,aes-ctr加密是使用aes对一个计数器加密,加密后获得密钥和我们的明文异或获得最终的密文,有一点类似于一次一密的加密方式,但是在这个题中编写程序的人使用多线程对其进行加密,而未对计数器进行多线程管理,导致有可能出现使用同一密钥对明文加密。所以我们用已知的明文和密文做异或猜测密钥,在使用密钥对密文解密

from Crypto.Cipher import AES
import binascii
def chunk(input_data, size):
    return [input_data[i:i + size] for i in range(0, len(input_data), size)]
def xor(*t):
    from functools import reduce
    from operator import xor
    return [reduce(xor, x, 0) for x in zip(*t)]


def xor_string(t1, t2):
    t1 = map(ord, t1)
    t2 = map(ord, t2)
    return "".join(map(chr, xor(t1, t2)))
miwen="9d5c66e65fae92af9c8a55d9d3bf640e8a5b76a878cbf691d3901392c9b8760ebd5c62b22c88dca9d1c55098cbbb644ae9406ba32c8293bdd29139bbc2b4605bba51238f2cb399a9d0894ad9cbb8774be9406ce66fae89a6c8ef7ad9c4b87442ad1470af78e19da6d8c55096d2b9750ea8586fe668a085c2ef8a5e9cd3be6c4bba144ae66ba488e8df84418bceb2650ea84362bf0688dcabd3905d8d87a46d414626be04a58215b84263a620de3203fa4626be08e2940da35c61b82c98201ce15438cd67eb921cf77c28a969de321bf4433ea24ca59216a25b7bb662996106e11639e75ae09015bb4c2fb76d8c254fe15e6ab45cea817391547cab698c6d4ff35039b34df7df599e412fb67fde3200b55432a441f19817b01405962c9d2e1af9556aa447f09f0df75360ad6988241db91129a85deb8559a25b7bb660de084ff1cc3a0e8041bc71d71fb29883931d9d3e8f784ca743b065c91ea386909e1a9100925f4fa742b1718c1efec4d4d609df5bcb3b17e417bd268d5fe6ced4d65b9c40d6305eeb1df03e9050e68bcad241dd15b46453b85dae7cd112b2c3c7ca50dd4ddf2c1ff350f5349c5febcadbd2509c40d6340aad03bd258d5bb2d8cdc647d814d1335efe18f8718651e7c5d6b9609c57d12010fe50e939801ee1dbcbd74cce4739c1eeceba8ef87360b629ed82a6eb9d508ee381bb88e97363bf20a1cfe7a7e07cccf3cea788bd277fb265e9cde4a9b937808aa7ee85f22679a365f5c4ede5f478c0e482ab95bd3c79f731e9c9a8b6ff7cc2e6c0e0c897047fb22ba1e5afa8b778c2ef80abcabd1a37b42af4c2fce5fa60dde582a8c7971a37b42af4c2fce5e475c1f782b7cabd207bb832edd5a4e5e4130a976ad4a2fe86ac99c18491f9f6c86adae59cc4a9f33072f70ca6daede5e40b049272c8e6b980b798c69e9fb7f7891611c7758df0fc82b481d1ca9eb8e2cd5f118f26def6f693d2abc99982bce2855f038175d9e7ebcdf8a4dcca9faab0da1045857eceebed8ab68a89e0bff9f3c60a098426ceedec8daccdce8584bce6cc0d49c065c2f7f797f898c69e9fb5b0e05f019269dd88a8c2f8df89cac5f8b09d00ad16dc760ead7c3518baed47603c5b5251cc269cae93d1f8a4888699aff58942c8529f304af0362143f2bd1e37670d538753992129ff3c6c5befb21e7331590c950ac26917be39644dfba50b2b70117fcbccba57b209ae95721a1c9d36073d934b75014109102be14fb6a044a7cf9e468748976457f6342177f5a9042630622f97d2ba5a8c04a7890d4e5fcb445b7600d7c1be71b711b6b32b4444f078557ef82e4f0559225437b455aa9a0bbaff89c834531a45115125c933d6cd6cdca8f8"
plaintext = """The Song of the Count

You know that I am called the Count
Because I really love to count
I could sit and count all day
Sometimes I get carried away
I count slowly, slowly, slowly getting faster
Once I've started counting it's really hard to stop
Faster, faster. It is so exciting!
I could count forever, count until I drop
1! 2! 3! 4!
1-2-3-4, 1-2-3-4,
1-2, i love couning whatever the ammount haha!
1-2-3-4, heyyayayay heyayayay that's the sound of the count
I count the spiders on the wall...
I count the cobwebs in the hall...
I count the candles on the shelf...
When I'm alone, I count myself!
I count slowly, slowly, slowly getting faster
Once I've started counting it's really hard to stop
Faster, faster. It is so exciting!
I could count forever, count until I drop
1! 2! 3! 4!
1-2-3-4, 1-2-3-4, 1,
2 I love counting whatever the
ammount! 1-2-3-4 heyayayay heayayay 1-2-3-4
That's the song of the Count!
"""



chunks=chunk(plaintext,16)

miwens=chunk(miwen,32)
for i in xrange(len(miwens)):
    miwens[i]=binascii.unhexlify(miwens[i])

key=[]
for i in xrange(len(chunks)):
    key.append(xor_string(chunks[i],miwens[i]))

   
for i in list(set(key)):
    ss=""
    for j in xrange(57,61):
        ss=ss+xor_string(i,miwens[j])
    print ss


2.elementary

我们使用ida打开程序,阅读发现这里的flag是103个字符组成,程序对103个字符中的每一位进行比较,当对应位function如下图所示,则表明该位为0

当对应位function如下图所示,则表明该位为1 

但由于这样的函数过多,我们猜想可不可以使用自动化工具求解,我们这里使用angr求解,代码如下

import angr
import claripy
START = 0x40071a # start of main
FIND  = 0x40077f # Good job message basic block
AVOID = [0x400786] # Wrong messages bassic block

BUF_LEN = 104

def char(state, c):
    return state.solver.And(c <= '~', c >= ' ')

def main():
    p = angr.Project("elementary")
    flag = claripy.BVS('flag', BUF_LEN * 8)
    state = p.factory.blank_state(addr=START, stdin=flag)
    for c in flag.chop(8):
        state.solver.add(char(state, c))
    ex = p.factory.simulation_manager(state)
    ex.use_technique(angr.exploration_techniques.Explorer(find=FIND, avoid=AVOID))
    ex.run()

    return ex.found[0].posix.dumps(0).decode("utf-8")
print(main())

结果如下:

3. Bro,do you even lift?

我们阅读源程序可知这里首先获取flag,将flag带入多项式环中结果为0,所以我们只需求解方程的解,这里modN的N过大,而N为p的100次方,我们可以先计算modp的解,然后升幂计算modN的结果:

计算modp的解:

p = 35671
k = 100
P.<x> = PolynomialRing(Zmod(p), implementation='NTL')
f = 12172655049735206766902704703038559858384636896299329359049381021748*x^4 + 11349632906292428218038992315252727065628405382223597973250830870345*x^3 + 9188725924715231519926481580171897766710554662167067944757835186451*x^2 + 8640134917502441100824547249422817926745071806483482930174015978801*x + 170423096151399242531943631075016082117474571389010646663163733960337669863762406085472678450206495375341400002076986312777537466715254543510453341546006440265217992449199424909061809647640636052570307868161063402607743165324091856116789213643943407874991700761651741114881108492638404942954408505222152223605412516092742190317989684590782541294253512675164049148557663016927886803673382663921583479090048005883115303905133335418178354255826423404513286728
print f.monic().roots()

这里使用lemma lifting提升modp的阶直至modN

import gmpy2
#原函数
def f(x):
    return gmpy2.mpz(12172655049735206766902704703038559858384636896299329359049381021748)*x**4 + gmpy2.mpz(11349632906292428218038992315252727065628405382223597973250830870345)*x**3 + gmpy2.mpz(9188725924715231519926481580171897766710554662167067944757835186451)*x**2 + gmpy2.mpz(8640134917502441100824547249422817926745071806483482930174015978801)*x + gmpy2.mpz(170423096151399242531943631075016082117474571389010646663163733960337669863762406085472678450206495375341400002076986312777537466715254543510453341546006440265217992449199424909061809647640636052570307868161063402607743165324091856116789213643943407874991700761651741114881108492638404942954408505222152223605412516092742190317989684590782541294253512675164049148557663016927886803673382663921583479090048005883115303905133335418178354255826423404513286728)
#函数求导
def df(x):
    return gmpy2.mpz(48690620198940827067610818812154239433538547585197317436197524086992)*x**3 + gmpy2.mpz(34048898718877284654116976945758181196885216146670793919752492611035)*x**2 + gmpy2.mpz(18377451849430463039852963160343795533421109324334135889515670372902)*x + gmpy2.mpz(8640134917502441100824547249422817926745071806483482930174015978801)
#Hensal's lifting lemma
def lift(p,k,basesolution):
    fr=f(basesolution)
    dfr=df(basesolution)
    if dfr%p!=0:
        dfrni=gmpy2.invert(dfr,p)
        t=(-dfrni*fr/pow(p,k-1))%p
        basesolution=basesolution+t*pow(p,k-1)
        return basesolution
    else:
        return -1
k=gmpy2.mpz(100)
solution=gmpy2.mpz(27020)
for i in range(2,k+1):
    if solution==-1:
        print "wrong"
        break
    solution=lift(gmpy2.mpz(35671),i,solution)

print hex(solution)[2:].decode("hex")

猜你喜欢

转载自blog.csdn.net/zhang14916/article/details/88661735
ctf