HGAME2020 Week2 Writeup

我太南了.jpg


Crypto - Verification_code

題目:

本週的簽到題 XP
nc 47.98.192.231 25678

還有一段服務端的腳本

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import socketserver
import os, sys, signal
import string, random
from hashlib import sha256

from secret import FLAG

class Task(socketserver.BaseRequestHandler):
    def _recvall(self):
        BUFF_SIZE = 2048
        data = b''
        while True:
            part = self.request.recv(BUFF_SIZE)
            data += part
            if len(part) < BUFF_SIZE:
                break
        return data.strip()

    def send(self, msg, newline=True):
        try:
            if newline: msg += b'\n'
            self.request.sendall(msg)
        except:
            pass

    def recv(self, prompt=b'> '):
        self.send(prompt, newline=False)
        return self._recvall()

    def proof_of_work(self):
        random.seed( os.urandom(8) )
        proof = ''.join([ random.choice(string.ascii_letters+string.digits) for _ in range(20) ])
        _hexdigest = sha256(proof.encode()).hexdigest()
        self.send(str.encode( "sha256(XXXX+%s) == %s" % (proof[4:],_hexdigest) ))
        x = self.recv(prompt=b'Give me XXXX: ')
        if len(x) != 4 or sha256(x+proof[4:].encode()).hexdigest() != _hexdigest: 
            return False
        return True

    def handle(self):
        signal.alarm(60)
        if not self.proof_of_work():
            return
        self.send(b'The secret code?')
        _code = self.recv()
        if _code == b'I like playing Hgame':
            self.send(b'Ok, you find me.')
            self.send(b'Here is the flag: ' + FLAG)
            self.send(b'Bye~')
        else:
            self.send(b'Rua!!!')
        self.request.close()

class ThreadedServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
    pass

class ForkedServer(socketserver.ForkingMixIn, socketserver.TCPServer):
    pass

if __name__ == "__main__":
    HOST, PORT = '0.0.0.0', 1234
    server = ForkedServer((HOST, PORT), Task)
    server.allow_reuse_address = True
    server.serve_forever()

先直接nc建立連接,返回結果如下

root@tesla:~/桌面/hg# nc 47.98.192.231 25678
sha256(XXXX+ggsSLHtrFoRrIeCk) == 4e5da0bdb510375747dd0bd1f1c18befee4d850c09624636c5daa1c0e7595249
Give me XXXX: 

題意應該是找對應的XXXX填上去就行了
由服務端的string.ascii_letters+string.digits可知XXXX的每個字符只有62種可能,因此直接爆破應該可行
然而實際操作的時候有一個問題,每一次nc建立連接得到的結果都不一樣,而且連上服務器之後只有60秒的時間找到XXXX,然而我在電腦上直接跑一輪暴力驗證很容易超時
之後在網上找了一下python多線程和多進程的教程,把時間縮短了一些,基本就能過了

腳本如下:

import string,sys
from hashlib import sha256
from multiprocessing import Process

table = (string.ascii_letters + string.digits).encode()
prefix = [string.ascii_lowercase.encode()[0:13],string.ascii_lowercase.encode()[13:26],string.ascii_uppercase.encode()[0:13],string.ascii_uppercase.encode()[13:26],string.digits.encode()]

def task(index,c,part):
    for i in prefix[index]:
        for j in table:
            for k in table:
                for l in table:
                    raw = i.to_bytes(1, 'big')
                    raw += j.to_bytes(1, 'big')
                    raw += k.to_bytes(1, 'big')
                    raw += l.to_bytes(1, 'big')
                    raw += part
                    if sha256(raw).hexdigest().encode() == c:
                        print(raw)

if __name__ == '__main__':
    c = input().encode()
    part = input().encode()
    for i in range(5):
        p=Process(target=task,args=(i,c,part))
        p.start()

最終flag:hgame{It3Rt0O|S+I5_u$3fu1~Fo2_6rUtE-f0Rc3}

後記:
最初想到的優化方法是使用多線程,但是經過測試多線程窮舉完所有字符的速度反而比單線程慢(後來得知可能是GIL的問題),於是改用多進程執行,速度就提上來了
flag當中提到的itertools是python中操作迭代對象的一個模塊,應該可以用來替換腳本當中的嵌套for,等有空去試一下
這道題不一定要用多進程來優化,添加與服務器直接交互的功能也能有效提升解題速度,或者是用單進程手動交互的腳本多試幾次,運氣好的話也能在60秒內解出來


Crypto - Remander

題目:

烤個孫子

還有加密腳本:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from Crypto.Util import number
from secret import msg

assert 256 < len(msg) < 384

p, q, r = [number.getPrime(1024) for _ in range(3)]
# p = 94598296305713376652540411631949434301396235111673372738276754654188267010805522542068004453137678598891335408170277601381944584279339362056579262308427544671688614923839794522671378559276784734758727213070403838632286280473450086762286706863922968723202830398266220533885129175502142533600559292388005914561
# q = 150088216417404963893679242888992998793257903343994792697939121738029477790454833496600101388493792476973514786401036309378542808470513073408894727406158296404360452232777491992630316999043165374635001806841520490997788796152678742544032835808854339130676283497122770901196468323977265095016407164510827505883
# r = 145897736096689096151704740327665176308625097484116713780050311198775607465862066406830851710261868913835866335107146242979359964945125214420821146670919741118254402096944139483988745450480989706524191669371208210272907563936516990473246615375022630708213486725809819360033470468293100926616729742277729705727

m = number.bytes_to_long(msg)
e = 65537
for prime in [p, q, r]:
    print( pow(m, e, prime) )

# 78430786011650521224561924814843614294806974988599591058915520397518526296422791089692107488534157589856611229978068659970976374971658909987299759719533519358232180721480719635602515525942678988896727128884803638257227848176298172896155463813264206982505797613067215182849559356336015634543181806296355552543 
# 49576356423474222188205187306884167620746479677590121213791093908977295803476203510001060180959190917276817541142411523867555147201992480220531431019627681572335103200586388519695931348304970651875582413052411224818844160945410884130575771617919149619341762325633301313732947264125576866033934018462843559419 
# 48131077962649497833189292637861442767562147447040134411078884485513840553188185954383330236190253388937785530658279768620213062244053151614962893628946343595642513870766877810534480536737200302699539396810545420021054225204683428522820350356470883574463849146422150244304147618195613796399010492125383322922

這題一開始找不到下手的地方,之後校內羣裏面出題人給了相關資料,結合題目的提示,大概知道是在考中國剩餘定理
然而得到m ^ e mod M(M=p * q * r)的值後就無從下手了,想試着直接開e次方根但由於mod M的原因無法求解,感覺m ^ e mod M和題目中直接給出的m ^ e mod p的值似乎沒有什麼區別,因此一直拖到ddl前一天都沒碰這道題
後來回想起week1中考RSA的題目當中也有pow(m, e, prime)和e,進一步思考,破解RSA的難點就在於分解公鑰中的n(本題中的M),而n在本題中已經可以被分解爲p、q和r,因此把e當作公鑰結合p、q和r即可算出私鑰,用RSA解密的流程即可得到明文m
在搜索過程當中還瞭解到,RSA當中用到的歐拉函數原始公式爲euler(x)=x * (1-1/p1) * (1-1/p2) * (1-1/p3) * (1-1/p4) * … * (1-1/pn),其中p1,p2……pn爲x的所有不重複素因數,因爲RSA算法當中的n只有p、q兩個素因子,代入公式即得euler(n)=(p-1)(q-1)。同理,本題中n(M)只有p、q和r三個素因子,代入公式可得euler(M)=(p-1)(q-1)(r-1)
最終的解密腳本如下:

import math, gmpy2
from gmpy2 import mpz

# 導入同餘式組的除數m與餘數a
a = []
a.append(mpz(78430786011650521224561924814843614294806974988599591058915520397518526296422791089692107488534157589856611229978068659970976374971658909987299759719533519358232180721480719635602515525942678988896727128884803638257227848176298172896155463813264206982505797613067215182849559356336015634543181806296355552543))
a.append(mpz(49576356423474222188205187306884167620746479677590121213791093908977295803476203510001060180959190917276817541142411523867555147201992480220531431019627681572335103200586388519695931348304970651875582413052411224818844160945410884130575771617919149619341762325633301313732947264125576866033934018462843559419))
a.append(mpz(48131077962649497833189292637861442767562147447040134411078884485513840553188185954383330236190253388937785530658279768620213062244053151614962893628946343595642513870766877810534480536737200302699539396810545420021054225204683428522820350356470883574463849146422150244304147618195613796399010492125383322922))

m = []
m.append(mpz(94598296305713376652540411631949434301396235111673372738276754654188267010805522542068004453137678598891335408170277601381944584279339362056579262308427544671688614923839794522671378559276784734758727213070403838632286280473450086762286706863922968723202830398266220533885129175502142533600559292388005914561))
m.append(mpz(150088216417404963893679242888992998793257903343994792697939121738029477790454833496600101388493792476973514786401036309378542808470513073408894727406158296404360452232777491992630316999043165374635001806841520490997788796152678742544032835808854339130676283497122770901196468323977265095016407164510827505883))
m.append(mpz(145897736096689096151704740327665176308625097484116713780050311198775607465862066406830851710261868913835866335107146242979359964945125214420821146670919741118254402096944139483988745450480989706524191669371208210272907563936516990473246615375022630708213486725809819360033470468293100926616729742277729705727))

# 使用中國剩餘定理,得到的res即爲m ^ e mod M
M = mpz(1)
res=mpz(0)
for i in m:
    M *= i
for i in range(len(m)):
    Mi = mpz(1)
    for j in m:
        if (j != m[i]):
            Mi*=j
    ti = gmpy2.invert(Mi, m[i])
    res += a[i] * ti * Mi
res %= M

# 求歐拉函數euler(M)
phi = mpz(1)
for i in m:
    phi*=i-1

# 求私鑰,明文
inv = gmpy2.invert(65537, phi)
res = pow(res, inv, M)
print(str(int(res).to_bytes(384,'big'),'utf8'))

獲得的明文如下:

1hAyuFoOUCamGW9BP7pGKCG81iSEnwAOM8x
********** DO NOT GUESS ME ********
hg In number theory,
am the Chinese
e{ remainder theorem
Cr states that if one
T_  knows the
w0 remainders of the
Nt Euclidean division
+6  of an integer n
Ot by several
h3 integers, then
R_ YOU CAN FIND THE
mE FLAG, ;D
!!
!}
********** USE YOUR BRAIN *********
cbl8KukOPUvpoe1LCpBchXHJTgmDknbFE2z

最終flag:hgame{CrT_w0Nt+6Oth3R_mE!!!}


Crypto - Inv

題目:

Does python "bytes" object have inverse?

還有加密腳本:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import gmpy2
from secret import Sbox, flag
assert set(range(256)) == set(Sbox)
assert flag.startswith(b'hgame{') and flag.endswith(b'}')

def Subs(S, X):
    return bytes([ S[x] for x in X ])

def Mul(A, B):
    assert len(A)==len(B)
    return Subs(A, B)

def Pow(X, E):
    Y = X
    E = bin(E)[3:]
    for e in E:
        Y = Mul(Y, Y)
        if e=='1':
            Y = Mul(X, Y)
    return Y

s = bytes(Sbox)

print( Pow(s, 595) )
print( Pow(s, 739) )
print( Subs(s, flag) )

# b'\xc8&\xc1E\xbe*\xc5\x84\xdb1\x05\x9b\xc0\xf2\xac/\x0b0\x8d\'\xc2b\x89\x93\xa6\xcd\xe1\x1b\xf4H\xffa\x90A\xf7,(\xea?\xa8\xa0\x8b\xf1\xf9"X\n\x86fj\x074\x7fBO\xd4F\xbd\xe6\xd9\xa7\xaf\x8a\x8c\xde\xab;!PT\x15)+w\xbc\x00>\xc6g\xc3\x85=9K\xb6<\xb7x\xaeUG\x83vk\xa9\xf6{\x03Y\x87\x14e\xfd\xed@i\xcc.\xd1\xebo\x106\xe2\xe7\xd7\xeeu\x9e\xfe\x95^R\xfb8\x04\xb4S\x16\xe0\xad\xd8\x98n\xca\xe4\xdd\xd2\xc7\x99l\xb3\\2L\xa3\x1d:_\x12\xb87\x17\x01\xb1#~q\x1c\t\xe8\xdar\xef\xcb\x0c\xe5\x80\xdf\xc9y\x0e`\xe9\x94\xd0\xcfW\x1f5\xf5h\xbf\xba\x91\xb9d\xfcM\x81\xec\x88\xb2c\x9f\xa4J|\xd3m\xd6s\xd5\x92\x9d\x9a3\xa2\xb5\xfa\x19N\xa1\x82][\xf8\x06\x13\xdcC\x1e\x1a\xaa\xc4tz\x08\x8f%$D\xbb\x97 \xce\x96V\xe3\x02I\x18\x11\x0f\r\xf3p\x8e\xa5Z-\xf0}\xb0Q\x9c'
# b'U\x17\x8aE\xa6\x19\xab\x7fd0\xd2)\xc0\xae\xcc/G_\xe3\'\r\xfb\xaf\x00\xb1hgi-\xc1\xffa\x8d\t&\x99k\x95\x93\xa8.\x07\xcd\x87\x01\xe8\x89\x86\xf6f48F\xdc\x96\xd4`P\xd6!\xfe\xc4B:\xd31C\x9f\x1dT{2c9\x0bY5#\xf7\xb8H\xe0Db\xb6wv\xe1\xbbI\x8f\x83l\x80\xa9\x04q\x03\xf0m\xf4\x1bp\x8e\xc6u\xfd\x16$\x06\xf9Z\xec\xa2\xcb\xd7V\xb9\xd1\xbdt^\xe7\xe2\xac\x18\xb4\x15=n\xad\xd8S+\xca\xeb\xdd\xd0;\x84\xe6\x08\x8c3\xb3\x90\x02\xc8}\xee\xea7K\x98\xde\x8b~\xcf\xfa\x11\n\xda\xa4L\xa3\x0cWQ\xdf\xc9yj\x9d\xe9\xfcJO\x1a\x1f\xdb\xf5M\xbf\x9e e\x1c*\x9b\x85\xe5\x88\xb2\xc7\xf2\x91\x10\x0e,\xd9<s\xd5\xef\xb0@|\xc3\xbc(\xb5"\xa1\x82\xa7[\xf8A\x13\x14\xc2\x1eN\xaao\xedr\xba\xcex]\x92\x05\x97\x12\xc5%\\\xb7>R\x9a\x94\x0fX\xf3\xbe?\xa5\xe4\xa0z\xf16\x81\x9c'
# b"\\-\xa5{\xb9\x85J @\xfa\x91\x0b\x88\r4I\x7f\xb9\xe5\r\xc0\x84\x8f\xa6\xc0i\xb0\xa4\x1b\x8fIw\x84'\xa2\xa4\x00\x91\x87\x10\r\\\x8c\x12'

基本上一整週都在做這道題,但其實是在week2ddl的前一個小時才找到了突破口

第一階段
一開始先是分析Pow、Mul和Subs三個函數,在一番瞎折騰後發現Mul函數滿足交換律(x)和結合律(未證明,只通過部分數據進行了驗證)
之後分析Pow函數,根據E = bin(E)[3:]去計算595和739的二進制表示,結果如下:

595(10)=‭1001010011‬(2)
739(10)=‭1011100011(2)‬

發現1010011和1100011極其相似,嘗試以此爲突破口求解,無果

第二階段
結合三個函數的名字以及Mul函數的性質,猜測Pow相當於求次方,而Mul相當於乘法
Pow整體看上去與快速冪十分相似,但是其從高位到低位的順序和常見快速冪算法中從低位到高位的順序不同,況且[3:]應該會丟失掉指數的高三位(其實不會),懷疑這個Pow是針對於Subs函數而寫的,並沒有通用性
不過驗證方法也很簡單,把Subs的函數體改爲return S * X,然後對數字調用Pow函數即可。驗證發現Pow函數的運算結果和正常求次方函數的結果居然是一致的?
對Pow函數進行調試分析,有了一些新發現。以指數595爲例,腳本當中的bin()函數返回的結果並不是想象中的1001010011,而是0b1001010011,從索引爲3的位置切片得到的結果E應該是001010011(被去掉的部分總是0b1)。而len(E)=9即爲循環的次數,對Y進行len(E)次平方操作後即可得到指數最高位(1000000000)對應的因式(2 ^ 9),與此同時,在第i次循環中遇到的“1”位於指數二進制表示的第len(E)-i+1位,經過len(E)-i次循環後即可得到對應的因式(2 ^ (len(E)-i))),整個運算與常見快速冪算法其實是雷同的
根據上述分析,本題已知針對於bytes的類乘法運算和求次方運算,以及s ^ 595,s ^ 739和s * flag的值,理論上需要求出s,並通過s求出flag
如果s與flag都是數字那麼本題就十分簡單了,對s ^ 595直接開595次方得到s,然後用flag/s即可得到結果。然而本題中並沒有給出針對bytes的開方運算或者類除法運算。嘗試了一下,似乎通過已知的Mul函數和Pow函數也無法構造出開方運算和類除法運算

第三階段
整理了一下之前的思路,不需要直接構造出開方運算,只要能構造出類除法運算那麼這題也能夠解出來
結合此題的題目描述,準確來說現在需要找到的是關於S的逆元T,也就是S ^ (-1),使得S * T=S * S ^ (-1)=1
這當中還有一個問題,“1”在這裏對應的bytes是什麼?根據數字1的性質,設“1”bytes爲E,E應該滿足Mul(X,E)=X(類似於矩陣當中的單位矩陣)。經過一些較短bytes的實驗,“1”對應的是b’\x00\x01\x02\x03……'這樣的與X等長的的bytes
在此期間校內羣裏面學長給出了這題的相關資料,並且提到了這題與共模攻擊有關。因爲求逆心切,以爲這段資料可以用來求逆,然而發現資料當中甚至涉及到新運算mod,進一步搜索有關共模攻擊的內容,發現使用共模攻擊時也需要用到逆元

第四階段
原本打算放棄這道題目,但在接近week2ddl時決定還是爭取一下
因爲c1=Pow(s, 595)和c2=Pow(s, 739)的長度均爲256,結合set(range(256)) == set(Sbox),猜測s以及s的冪均爲’\x00’ ~ '\xff’的某種排列
一開始腦子迷糊了想直接爆破出c1的逆元,通過簽到題提示的itertools很快構建出了爆破腳本。但在爆破了將近10分鐘後突然意識到了爆破涉及的運算量,於是放棄了直接爆破的操作
抱着試試看的心態對幾個長度較短的bytes進行爆破求逆元,並嘗試觀察逆元與原bytes的關係
獲得的幾組數據如下:

b'\x06\x02\x00\x05\x04\x03\x07\x01'
(2, 7, 1, 5, 4, 3, 0, 6)

b'\x01\x07\x00\x05\x02\x06\x03\x04'
(2, 0, 4, 6, 7, 3, 5, 1)

b'\x00\x02\x04\x01\x03\x06\x05\x07'
(0, 3, 1, 4, 2, 6, 5, 7)

觀察得到以下規律:
設原bytes爲S,其逆元爲T,則對於i ∈ range(len(S)),總有T[S[i]]=i
由此構建出求逆函數Inv()如下:

def Inv(S):
    l=len(S)
    e = list(range(l))
    res = list(range(l))
    pre=list(S)
    for i in range(l):
        res[pre[i]]=e[i]
    return bytes(res)

之後用學長說的共模攻擊求解。題目中雖然沒有提到公共模數n,但是我們可以假設n=595 * 739 * x,x的值非常大以至於運算過程中是否對n取模不影響結果。這樣在形式上就滿足RSA的共模攻擊了。具體實施的時候參考了這篇文章
解題代碼如下:

def Subs(S, X):
    return bytes([S[x] for x in X])

def Mul(A, B):
    return Subs(A, B)

def Pow(X, E):
    Y = X
    E = bin(E)[3:]
    for e in E:
        Y = Mul(Y, Y)
        if e=='1':
            Y = Mul(X, Y)
    return Y

def Inv(S):
    l=len(S)
    e = list(range(l))
    res = list(range(l))
    pre=list(S)
    for i in range(l):
        res[pre[i]]=e[i]
    return bytes(res)

c1=b'\xc8&\xc1E\xbe*\xc5\x84\xdb1\x05\x9b\xc0\xf2\xac/\x0b0\x8d\'\xc2b\x89\x93\xa6\xcd\xe1\x1b\xf4H\xffa\x90A\xf7,(\xea?\xa8\xa0\x8b\xf1\xf9"X\n\x86fj\x074\x7fBO\xd4F\xbd\xe6\xd9\xa7\xaf\x8a\x8c\xde\xab;!PT\x15)+w\xbc\x00>\xc6g\xc3\x85=9K\xb6<\xb7x\xaeUG\x83vk\xa9\xf6{\x03Y\x87\x14e\xfd\xed@i\xcc.\xd1\xebo\x106\xe2\xe7\xd7\xeeu\x9e\xfe\x95^R\xfb8\x04\xb4S\x16\xe0\xad\xd8\x98n\xca\xe4\xdd\xd2\xc7\x99l\xb3\\2L\xa3\x1d:_\x12\xb87\x17\x01\xb1#~q\x1c\t\xe8\xdar\xef\xcb\x0c\xe5\x80\xdf\xc9y\x0e`\xe9\x94\xd0\xcfW\x1f5\xf5h\xbf\xba\x91\xb9d\xfcM\x81\xec\x88\xb2c\x9f\xa4J|\xd3m\xd6s\xd5\x92\x9d\x9a3\xa2\xb5\xfa\x19N\xa1\x82][\xf8\x06\x13\xdcC\x1e\x1a\xaa\xc4tz\x08\x8f%$D\xbb\x97 \xce\x96V\xe3\x02I\x18\x11\x0f\r\xf3p\x8e\xa5Z-\xf0}\xb0Q\x9c'
c2=b'U\x17\x8aE\xa6\x19\xab\x7fd0\xd2)\xc0\xae\xcc/G_\xe3\'\r\xfb\xaf\x00\xb1hgi-\xc1\xffa\x8d\t&\x99k\x95\x93\xa8.\x07\xcd\x87\x01\xe8\x89\x86\xf6f48F\xdc\x96\xd4`P\xd6!\xfe\xc4B:\xd31C\x9f\x1dT{2c9\x0bY5#\xf7\xb8H\xe0Db\xb6wv\xe1\xbbI\x8f\x83l\x80\xa9\x04q\x03\xf0m\xf4\x1bp\x8e\xc6u\xfd\x16$\x06\xf9Z\xec\xa2\xcb\xd7V\xb9\xd1\xbdt^\xe7\xe2\xac\x18\xb4\x15=n\xad\xd8S+\xca\xeb\xdd\xd0;\x84\xe6\x08\x8c3\xb3\x90\x02\xc8}\xee\xea7K\x98\xde\x8b~\xcf\xfa\x11\n\xda\xa4L\xa3\x0cWQ\xdf\xc9yj\x9d\xe9\xfcJO\x1a\x1f\xdb\xf5M\xbf\x9e e\x1c*\x9b\x85\xe5\x88\xb2\xc7\xf2\x91\x10\x0e,\xd9<s\xd5\xef\xb0@|\xc3\xbc(\xb5"\xa1\x82\xa7[\xf8A\x13\x14\xc2\x1eN\xaao\xedr\xba\xcex]\x92\x05\x97\x12\xc5%\\\xb7>R\x9a\x94\x0fX\xf3\xbe?\xa5\xe4\xa0z\xf16\x81\x9c'
flag=b'\\-\xa5{\xb9\x85J @\xfa\x91\x0b\x88\r4I\x7f\xb9\xe5\r\xc0\x84\x8f\xa6\xc0i\xb0\xa4\x1b\x8fIw\x84\'\xa2\xa4\x00\x91\x87\x10\r\\\x8c\x12'

s1 = -272
s2 = 219

invc1 = Inv(c1)

s = Mul(Pow(invc1, -s1), Pow(c2, s2))
invs = Inv(s)
print(Subs(invs,flag))

當中的s1,s2是直接在WolframAlpha當中輸入595x+739y=1求解的
因爲Mul函數要求兩個參數等長,所以最後求flag的時候用的是Subs函數,並且經嘗試invs必須作爲第一個參數,否則會提示下標過界(此時Subs函數不滿足交換律)
原始腳本中提供的Subs(s,flag)爲

b"\\-\xa5{\xb9\x85J @\xfa\x91\x0b\x88\r4I\x7f\xb9\xe5\r\xc0\x84\x8f\xa6\xc0i\xb0\xa4\x1b\x8fIw\x84'\xa2\xa4\x00\x91\x87\x10\r\\\x8c\x12'

直接用於解密會出錯,嘗試將其改爲字符串,發現無法進行運算,後經過微調(前後引號匹配,中間的單引號加轉義字符),改爲

b'\\-\xa5{\xb9\x85J @\xfa\x91\x0b\x88\r4I\x7f\xb9\xe5\r\xc0\x84\x8f\xa6\xc0i\xb0\xa4\x1b\x8fIw\x84\'\xa2\xa4\x00\x91\x87\x10\r\\\x8c\x12'

即可得到flag
最終flag:hgame{U_kN0w~tH3+eXtEnD-EuC1iD34n^A1G0rIthM}

後記:
其實也沒有用擴展歐幾里得算法求解(因爲還是不太懂)(WolframAlpha萬歲!!!)
寫wp的時候結合資料來看整個題目,難點還是在於求逆,在完成求逆的函數之後,通過已知的s ^ 595,s ^ 739以及求逆得到的s ^ (-595),s ^ (-739)可以通過各種拼湊得到s ^ (-1),進而還原出flag
爲什麼可以湊出s ^ (-1)呢,因爲由裴蜀(貝祖)定理可得,對於整數a,b,一定存在一對x,y ∈ Z,使得ax+by=gcd(a,b),本題中的595與739互質,也就是說找得到一組整數x,y使得595x+739y=1,進而可以得到s ^ (595x+739y)=(s ^ 595) ^ x * (s ^ 739) ^ y=s ^ 1,因此(s ^ 595) ^ (-x) * (s ^ 739) ^ (-y)=s ^ (-1)。觀察式子不難發現這一組x,y必定是異號的,而求逆就是爲了計算s的負指數次冪
換一個角度來想,如果出題人給出的是Pow(s,466),Pow(s,844)和Subs(Pow(s,2),flag)(存在gcd(466,844)=2),那麼本題也應該可以求解(吧)
感覺這道題並沒有利用到共模攻擊當中模相同所帶來的一系列性質,只是沿用了一下求解的部分過程
最後驗證下來Mul函數不滿足交換律,之前驗證的時候直接用了s ^ 595和s ^ 739,所以誤以爲滿足交換律


Misc - 所見即爲假

題目:

真亦假,假亦真,真真假假,假假真真;
實亦虛,虛亦實,實實虛虛,虛虛實實。

ObjectNotFound給了你一個壓縮包和一副對子,轉身離開了。

打開壓縮包發現裏面有一張加密的圖片

同時壓縮包註釋裏面有以下內容:

F5 key: NllD7CQon6dBsFLr

以NllD7CQon6dBsFLr爲密碼打開壓縮包,失敗
把NllD7CQon6dBsFLr進行base64解碼,得到一串非常奇怪的字符,猜測應該不是密碼
後來想到題目中的對子,可能flag不在圖片裏面,而是以類似圖種的方式隱藏在壓縮文件頭部,遂用16進制編輯器打開壓縮包並和網上的zip包特徵一一比對,發現文件頭部和尾部與zip文件特徵相同,於是排除了這種可能

不過在比對zip包特徵時發現了一個異常情況,正常的加密zip文件頭部應該是

50 4B 03 04 14 00 09 00

而題目壓縮文件的頭部是

50 4B 03 04 14 00 00 00

百度了一下,zip文件存在僞加密的情況,遇到這種文件通常只需要把文件中的

50 4B 01 02 3F 00 14 00 09 00

改爲

50 4B 01 02 3F 00 14 00 00 00

即可(更改壓縮源文件目錄區的全局方式位標記)
經過上述修改後成功解壓出了圖片,按照網上的教程用stegsolve的各個功能跑了一遍,似乎沒有發現什麼東西(其實有東西)
懷疑出題人沒有把flag放到圖片裏面,爲了證實這一點,按照week1的方法用識圖平臺找到了原圖,通過比較文件大小,確定出題人在圖片上面動過手腳(題目圖片大小大於原始圖片大小),否定了這一猜測
用16進制編輯器打開兩張圖片,發現兩張圖片都有正常的jpg頭部和尾部(FF D8和FF D9),但是題目圖片的頭部多了以下內容:

AJPEG Encoder Copyright 1998, James R. Weeks and BioElectroMech

之前用stegsolve的時候也看到了這段文字,但是沒有意識到裏面有問題,百度發現這是使用過基於F5算法的隱寫軟件的特徵,結合zip包註釋中的F5 key,基本確定這是圖像隱寫題
百度F5隱寫的相關內容,在github上clone了一個相關工具,用對應的F5 key解碼獲得了以下內容

526172211A0701003392B5E50A01050600050101808000B9527AEA2402030BA70004A70020CB5BDC2D80000008666C61672E7478740A03029A9D6C65DFCED5016867616D657B343038375E7A236D737733344552746E46557971704B556B32646D4C505736307D1D77565103050400

看到裏面只出現了大寫字母和數字,懷疑是base32或者base16編碼,經過測試發現base32解碼失敗(base32中只有A ~ Z,2 ~ 7和=),base16解碼得到以下內容

b'Rar!\x1a\x07\x01\x003\x92\xb5\xe5\n\x01\x05\x06\x00\x05\x01\x01\x80\x80\x00\xb9Rz\xea$\x02\x03\x0b\xa7\x00\x04\xa7\x00 \xcb[\xdc-\x80\x00\x00\x08flag.txt\n\x03\x02\x9a\x9dle\xdf\xce\xd5\x01hgame{4087^z#msw34ERtnFUyqpKUk2dmLPW60}\x1dwVQ\x03\x05\x04\x00'

之前的題目當中總是出現Rua!而解碼的結果卻是Rar!,懷疑這串文本需要進一步解密,但是結果中直接出現了hgame{…},經過嘗試這就是flag
最終flag:hgame{4087^z#msw34ERtnFUyqpKUk2dmLPW60}

後記:
百度得知52617221是rar文件頭部的標誌,正常操作應該是將F5解碼的結果輸出爲二進制的RAR文件打開,得到含有flag的文本文件


Misc - 地球上最後的夜晚

題目:

農曆一年中最後的夜晚馬上就要來臨了。
唔...“最後的夜晚”...這讓我想起了去年春節前夕。
一個“上”字,區分開了名著《地球上最後的夜晚》,和畢贛導演的《地球最後的夜晚》。
一年了,ObjectNotFound手裏的那本《地球上最後的夜晚》,還沒有看完...

這道題總體來說難度不高。打開壓縮包看到有一個pdf文件和另一個加密的壓縮包,先嚐試改後綴爲zip以及用binwalk和strings搜索,無果。之後查資料得知pdf文件可用wbStego進行信息隱寫,於是下載工具解密得到以下內容:

Zip Password: OmR#O12#b3b%s*IW

打開加密的壓縮包,得到一個docx文件。先是找了一下文檔當中的隱藏文字,沒有結果。考慮到docx文件本質上是一個壓縮包,於是改後綴名爲zip並在壓縮包內搜索,最後在\word\secret.xml當中找到了flag
最終flag:hgame{mkLbn8hP2g!p9ezPHqHuBu66SeDA13u1}


Misc - Cosmos的午餐

題目:

Cosmos做夢都想吃一次芽衣親手做的午餐,邊吃飯邊左擁八重櫻右抱希兒這種。
他在屏幕前對着圖片做白日夢的樣子恰巧被路過的ObjectNotFound看到了。
“唔...好香呀!”
“Cosmos!醒醒!別睡了!!起來做PWN了!!!”
PS: Cosmos經常往圖片備註裏塞東西。

壓縮包裏面有一個Wireshark的抓包文件和SSL的log文件
在看完上個星期的官方wp後,我大概掌握了pcapng文件的處理方法(然而接下來出了很多錯)。同時包裏面的SSL文件肯定不是白給,於是直接百度“wireshark ssl”,找到了分析pcapng中https包的方法
(編輯→首選項→Protocols→TLS(或者是SSL)當中指定SSL的log文件路徑)

先在過濾器中輸入http篩選所有的http包,在分組列表中按照大小排序,找到大小爲8291的一個可疑包,通過查看Decrypted TLS數據發現末尾部分有Outgess with key.jpg,同時還有兩個PK出現(zip文件標誌),推測可以通過導出zip文件進行下一步操作,於是直接將Transport Layer Security→TLS segment data部分(大小爲8208)導出爲二進制文件,結果無法打開文件

查看導出文件,發現缺少zip文件的頭部特徵,但是無論怎麼補頭都無法打開,考慮到week2應該不會出過於變態的補文件頭題目,於是懷疑自己導出的文件有問題
後進入文件→導出對象→HTTP…,在HTTP對象列表中按照大小排序,找到大小爲1220kB的文件,導出後成功作爲zip文件打開,得到一張圖片,結合題目提示和文件名,在圖片備註中獲得了用於解密的key:

gUNrbbdR9XhRBDGpzz

之後clone Outguess解密工具並編譯安裝,將圖片解密得到一個網址

https://dwz.cn/69rOREdu

下載了一個叫ScanMe的壓縮包,打開之後是一張被魔改過的二維碼

直接掃描識別失敗,根據圖片上的小點來分析,應該需要把圖上除HGAME和Vidar Logo以外的所有小點替換爲大點才能夠使掃碼軟件識別它
手動替換之後的結果如下(不會寫腳本的痛)

掃碼即可獲得flag
最終flag:hgame{ls#z^$7j%yL9wmObZ#MKZKM7!nGnDvTC}

後記:
在成功獲得flag後繼續對原pcapng文件進行分析,發現封包中zip文件是被拆成若干個segments發送的,而在分組列表當中顯示的包長度以及Decrypted TLS對應的大小似乎只與最後一個segment有關,第一次導出文件時只得到了zip文件的尾部(含有兩個PK標記,但是缺少頭部,文件大小也遠小於實際zip文件大小)也可以說明這一點

目前有個處理圖片的簡單思路:對圖中每個9 * 9的區域進行識別,如果該區域只有中心的3 * 3爲黑色而其餘部分爲白色,則將整個區域塗爲黑色。因爲二維碼中間嵌入了Vidar Logo和HGAME的字樣,其原始圖片的容錯率應該是比較高的,因此含有Vidar Logo和HGAME的部分即使沒有被正確編碼也不要緊。由於目前沒怎麼接觸過python的圖像處理功能,所以短時間內寫不出腳本


第二次做CTF類的題目,感覺自己更菜了,做出來的題目只有1/4,而且用時太長
Crypto出題人Lurkrul大佬tql

2020.01.31

發佈了26 篇原創文章 · 獲贊 0 · 訪問量 4250
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章