2019. 10. 14. 22:16, CTF/Crypto
prob.hs
import Data.Char
import System.IO
n :: Integer
n = 134896036104102133446208954973118530800743044711419303630456535295204304771800100892609593430702833309387082353959992161865438523195671760946142657809228938824313865760630832980160727407084204864544706387890655083179518455155520501821681606874346463698215916627632418223019328444607858743434475109717014763667
k :: Int
k = 131
primes :: [Integer]
primes = take k $ sieve (2 : [3, 5..])
where
sieve (p:xs) = p : sieve [x|x <- xs, x `mod` p > 0]
stringToInteger :: String -> Integer
stringToInteger str = foldl (\x y -> (toInteger $ ord y) + x*256) 0 str
integerToString :: Integer -> String
integerToString num = f num ""
where
f 0 str = str
f num str = f (div num 256) $ (:) (chr $ fromIntegral $ num `mod` 256) str
numToBits :: Integer -> [Int]
numToBits num = f num []
where
f 0 arr = arr
f x arr = f (div x 2) ((fromInteger $ x `mod` 2) : arr)
extendBits :: Int -> [Int] -> [Int]
extendBits blockLen arr
| len == 0 = arr
| len > 0 = (replicate (blockLen-len) 0) ++ arr
where len = (length arr) `mod` blockLen
calc :: Integer -> [Int] -> Integer
calc num [] = num
calc num arr = calc result restArr
where
num2 = num*num `mod` n
(block, restArr) = splitAt k arr
zipped = zipWith (\x y -> ((fromIntegral x)*y) `mod` n) block primes
mul = product $ filter (/=0) zipped
result = num2*mul `mod` n
magic :: String -> String
magic input = result
where
num = stringToInteger input
bits = numToBits num
extended = reverse $ extendBits 8 bits
oriLen = length extended
extendedBits = extendBits k extended
oriLenBits = numToBits $ fromIntegral oriLen
extendedOriLenBits = extendBits k oriLenBits
finalBits = extendedOriLenBits ++ extendedBits
result = show $ calc 1 (reverse finalBits)
main = do
flag <- readFile "flag"
putStrLn.show $ length flag
putStrLn $ magic ("the flag is hitcon{" ++ flag ++ "}")
Output
6
84329776255618646348016649734028295037597157542985867506958273359305624184282146866144159754298613694885173220275408231387000884549683819822991588176788392625802461171856762214917805903544785532328453620624644896107723229373581460638987146506975123149045044762903664396325969329482406959546962473688947985096
Since I'm not that familiar with haskell, I waste a lot of time to understand the logic. The logic is not that hard. It is a Naccache-Stern Knapsack Cryptosystem. Some wise guy in GoN ports haskell code to python, so if you are interested, you can check it.
The candidates of flag are total $10^{12}$. But using Meet-In-The-Middle, You can solve it in $O(10^6log(10^6))$.
Solver.py
from Crypto.Util.number import *
import string
n = 134896036104102133446208954973118530800743044711419303630456535295204304771800100892609593430702833309387082353959992161865438523195671760946142657809228938824313865760630832980160727407084204864544706387890655083179518455155520501821681606874346463698215916627632418223019328444607858743434475109717014763667
k = 131
enc = 84329776255618646348016649734028295037597157542985867506958273359305624184282146866144159754298613694885173220275408231387000884549683819822991588176788392625802461171856762214917805903544785532328453620624644896107723229373581460638987146506975123149045044762903664396325969329482406959546962473688947985096
prlist = []
for i in range(2,1000000):
if isPrime(i): prlist.append(i)
if len(prlist) == k: break
def calc1(L1, L2):
L1.reverse()
val = 1
for i in range(0, len(L1), k):
print(i)
val = val*val%n
for j in range(0,k):
if L1[i+j] == 1: val = val * prlist[j] % n
L2.reverse()
for i in range(0, len(L2), k):
val = val*val%n
for j in range(0,k):
if L2[i+j] == 1: val = val * prlist[j] % n
return val
base = 129105988525739869308153101831605950072860268575706582195774923614094296354415364173823406181109200888049609207238266506466864447780824680862439187440797565555486108716502098901182492654356397840996322893263870349262138909453630565384869193972124927953237311411285678188486737576555535085444384901167109670365
target = enc * inverse(base, n)
D = dict()
for a1 in string.printable:
for a2 in string.printable:
for a3 in string.printable:
i = bytes_to_long((a1+a2+a3).encode())
s = bin(i)[2:].zfill(24)
val = 1
for j in range(24):
if s[j]=='1':
val = val * prlist[j+21] * prlist[j+21] % n
D[val] = a1+a2+a3
for a1 in string.printable:
print("now2 ", a1)
for a2 in string.printable:
for a3 in string.printable:
i = bytes_to_long((a1+a2+a3).encode())
s = bin(i)[2:].zfill(24)
val = 1
for j in range(24):
if s[j]=='1':
val = val * prlist[j+45] * prlist[j+45] % n
tt = target * inverse(val, n) % n
if tt in D:
print("flag : hitcon{"+D[tt]+a1+a2+a3+"}")
'CTF > Crypto' 카테고리의 다른 글
[2019 X-MAS CTF] Santa Knows Crypto (0) | 2019.12.14 |
---|---|
[2019 X-MAS CTF] Hashed Presents (0) | 2019.12.14 |
[2019 X-MAS CTF] DeFUNct Ransomware (0) | 2019.12.14 |
[HITCON CTF 2019 Quals] Lost Modulus Again (2) | 2019.10.14 |
[TWCTF 2019] M-Poly-Cipher (0) | 2019.09.02 |
[TWCTF 2019] Simple Logic (0) | 2019.09.02 |
Comments