FwordCTF 2020 Writeup

この大会は2020/8/30 11:00(JST)~2020/8/31 11:00(JST)に開催されました。
今回もチームで参戦。結果は3813点で360チーム中59位でした。
自分で解けた問題をWriteupとして書いておきます。

Memory (Forensics)

コンピュータ名、ユーザ名、パスワードを答える必要がある。

$ volatility -f foren.raw imageinfo
Volatility Foundation Volatility Framework 2.6
INFO    : volatility.debug    : Determining profile based on KDBG search...
          Suggested Profile(s) : Win7SP1x64, Win7SP0x64, Win2008R2SP0x64, Win2008R2SP1x64_23418, Win2008R2SP1x64, Win7SP1x64_23418
                     AS Layer1 : WindowsAMD64PagedMemory (Kernel AS)
                     AS Layer2 : FileAddressSpace (/mnt/hgfs/Shared/work/foren.raw)
                      PAE type : No PAE
                           DTB : 0x187000L
                          KDBG : 0xf80002c48120L
          Number of Processors : 4
     Image Type (Service Pack) : 1
                KPCR for CPU 0 : 0xfffff80002c4a000L
                KPCR for CPU 1 : 0xfffff88002f00000L
                KPCR for CPU 2 : 0xfffff88002f7d000L
                KPCR for CPU 3 : 0xfffff880009af000L
             KUSER_SHARED_DATA : 0xfffff78000000000L
           Image date and time : 2020-08-26 09:22:27 UTC+0000
     Image local date and time : 2020-08-26 02:22:27 -0700

$ volatility -f foren.raw  --profile=Win7SP1x64 pstree
Volatility Foundation Volatility Framework 2.6
Name                                                  Pid   PPid   Thds   Hnds Time
-------------------------------------------------- ------ ------ ------ ------ ----
 0xfffffa801af105c0:explorer.exe                     1000   1332     31    896 2020-08-26 09:11:21 UTC+0000
. 0xfffffa801b024780:WzPreloader.ex                  2264   1000      6    123 2020-08-26 09:11:21 UTC+0000
. 0xfffffa801adeaa40:mspaint.exe                     1044   1000      7    133 2020-08-26 09:20:28 UTC+0000
. 0xfffffa801aca4060:chrome.exe                      3700   1000     33    986 2020-08-26 09:12:48 UTC+0000
.. 0xfffffa801af86b00:chrome.exe                     2560   3700     13    337 2020-08-26 09:12:48 UTC+0000
.. 0xfffffa8019ac0640:chrome.exe                     3992   3700     14    216 2020-08-26 09:13:33 UTC+0000
.. 0xfffffa8018e55b00:chrome.exe                     3304   3700      8    231 2020-08-26 09:12:50 UTC+0000
.. 0xfffffa8019b5b5f0:chrome.exe                      540   3700     13    171 2020-08-26 09:13:21 UTC+0000
.. 0xfffffa801ab9c750:chrome.exe                     3752   3700      8     93 2020-08-26 09:12:48 UTC+0000
.. 0xfffffa8019b60060:chrome.exe                     3816   3700     13    195 2020-08-26 09:13:22 UTC+0000
.. 0xfffffa8019a5b360:chrome.exe                     3528   3700     11    209 2020-08-26 09:12:55 UTC+0000
.. 0xfffffa8019b2ab00:chrome.exe                      616   3700     26    332 2020-08-26 09:13:21 UTC+0000
.. 0xfffffa8019b6fb00:chrome.exe                     2516   3700     17    294 2020-08-26 09:13:32 UTC+0000
. 0xfffffa8019bf7060:DumpIt.exe                      1764   1000      2     52 2020-08-26 09:22:18 UTC+0000
 0xfffffa801a74db00:wininit.exe                       388    348      3     84 2020-08-26 09:10:27 UTC+0000
. 0xfffffa801a74e7e0:services.exe                     488    388      8    232 2020-08-26 09:10:27 UTC+0000
.. 0xfffffa801aaba450:svchost.exe                    3308    488     14    339 2020-08-26 09:12:31 UTC+0000
.. 0xfffffa801abff060:svchost.exe                    1240    488     18    311 2020-08-26 09:10:29 UTC+0000
.. 0xfffffa801aa64510:svchost.exe                     900    488     38   1047 2020-08-26 09:10:27 UTC+0000
... 0xfffffa8019bf2060:wuauclt.exe                   1876    900      3     98 2020-08-26 09:13:33 UTC+0000
.. 0xfffffa8019bc0b00:svchost.exe                    3284    488      7    110 2020-08-26 09:20:28 UTC+0000
.. 0xfffffa801a9e6b00:svchost.exe                     680    488      8    298 2020-08-26 09:10:27 UTC+0000
.. 0xfffffa801a976b00:mscorsvw.exe                   4012    488      6     93 2020-08-26 09:12:30 UTC+0000
.. 0xfffffa801b3211e0:svchost.exe                    2996    488     10    366 2020-08-26 09:11:29 UTC+0000
.. 0xfffffa801ab61b00:svchost.exe                    1336    488     10    147 2020-08-26 09:10:30 UTC+0000
.. 0xfffffa801aecf5f0:taskhost.exe                   2036    488     10    234 2020-08-26 09:11:20 UTC+0000
.. 0xfffffa8018e10b00:spoolsv.exe                    1212    488     14    299 2020-08-26 09:10:29 UTC+0000
.. 0xfffffa801ab66b00:svchost.exe                    1096    488     16    480 2020-08-26 09:10:29 UTC+0000
.. 0xfffffa801ae2e060:sppsvc.exe                     1360    488      4    151 2020-08-26 09:10:34 UTC+0000
.. 0xfffffa8018e4f4f0:svchost.exe                    1748    488      7    104 2020-08-26 09:10:30 UTC+0000
.. 0xfffffa801a9bb060:svchost.exe                     600    488     11    367 2020-08-26 09:10:27 UTC+0000
... 0xfffffa801a5f95f0:WmiPrvSE.exe                   952    600      5    120 2020-08-26 09:11:30 UTC+0000
.. 0xfffffa801ae824b0:mscorsvw.exe                   4052    488      6     83 2020-08-26 09:12:31 UTC+0000
.. 0xfffffa801aa4a860:svchost.exe                     864    488     22    574 2020-08-26 09:10:27 UTC+0000
.. 0xfffffa801b20fb00:wmpnetwk.exe                   2768    488     14    494 2020-08-26 09:11:28 UTC+0000
.. 0xfffffa801ac9bb00:svchost.exe                    1388    488     22    340 2020-08-26 09:10:30 UTC+0000
.. 0xfffffa801aa34b00:svchost.exe                     808    488     26    533 2020-08-26 09:10:27 UTC+0000
... 0xfffffa8019f45870:dwm.exe                       1604    808      3     80 2020-08-26 09:11:20 UTC+0000
.. 0xfffffa801a9ecb00:svchost.exe                     756    488     23    588 2020-08-26 09:10:27 UTC+0000
... 0xfffffa801aa879b0:audiodg.exe                    968    756      8    148 2020-08-26 09:10:28 UTC+0000
.. 0xfffffa801aec4480:SearchIndexer.                 2644    488     13    711 2020-08-26 09:11:27 UTC+0000
.. 0xfffffa801aab6410:TrustedInstall                 1020    488      5    147 2020-08-26 09:10:28 UTC+0000
. 0xfffffa801a5f3b00:lsass.exe                        496    388     10    752 2020-08-26 09:10:27 UTC+0000
. 0xfffffa801a79a550:lsm.exe                          504    388     10    147 2020-08-26 09:10:27 UTC+0000
 0xfffffa801a738060:csrss.exe                         356    348     10    459 2020-08-26 09:10:26 UTC+0000
 0xfffffa8018da8040:System                              4      0    103    585 2020-08-26 09:10:17 UTC+0000
. 0xfffffa8019ebdb00:smss.exe                         264      4      2     32 2020-08-26 09:10:17 UTC+0000
 0xfffffa801a72fa00:csrss.exe                         404    380      9    384 2020-08-26 09:10:27 UTC+0000
. 0xfffffa801b2ad060:conhost.exe                     2592    404      2     56 2020-08-26 09:22:18 UTC+0000
 0xfffffa801a763930:winlogon.exe                      448    380      5    122 2020-08-26 09:10:27 UTC+0000
 0xfffffa801b01d480:FAHWindow64.ex                   2252   2240      2     77 2020-08-26 09:11:21 UTC+0000

$ volatility -f foren.raw  --profile=Win7SP1x64 envars | grep explorer
Volatility Foundation Volatility Framework 2.6
    1000 explorer.exe         0x0000000003727080 ALLUSERSPROFILE                C:\ProgramData
    1000 explorer.exe         0x0000000003727080 APPDATA                        C:\Users\SBA_AK\AppData\Roaming
    1000 explorer.exe         0x0000000003727080 CommonProgramFiles             C:\Program Files\Common Files
    1000 explorer.exe         0x0000000003727080 CommonProgramFiles(x86)        C:\Program Files (x86)\Common Files
    1000 explorer.exe         0x0000000003727080 CommonProgramW6432             C:\Program Files\Common Files
    1000 explorer.exe         0x0000000003727080 COMPUTERNAME                   FORENWARMUP
    1000 explorer.exe         0x0000000003727080 ComSpec                        C:\Windows\system32\cmd.exe
    1000 explorer.exe         0x0000000003727080 FP_NO_HOST_CHECK               NO
    1000 explorer.exe         0x0000000003727080 HOMEDRIVE                      C:
    1000 explorer.exe         0x0000000003727080 HOMEPATH                       \Users\SBA_AK
    1000 explorer.exe         0x0000000003727080 LOCALAPPDATA                   C:\Users\SBA_AK\AppData\Local
    1000 explorer.exe         0x0000000003727080 LOGONSERVER                    \\FORENWARMUP
    1000 explorer.exe         0x0000000003727080 NUMBER_OF_PROCESSORS           4
    1000 explorer.exe         0x0000000003727080 OS                             Windows_NT
    1000 explorer.exe         0x0000000003727080 Path                           C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\
    1000 explorer.exe         0x0000000003727080 PATHEXT                        .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
    1000 explorer.exe         0x0000000003727080 PROCESSOR_ARCHITECTURE         AMD64
    1000 explorer.exe         0x0000000003727080 PROCESSOR_IDENTIFIER           Intel64 Family 6 Model 94 Stepping 3, GenuineIntel
    1000 explorer.exe         0x0000000003727080 PROCESSOR_LEVEL                6
    1000 explorer.exe         0x0000000003727080 PROCESSOR_REVISION             5e03
    1000 explorer.exe         0x0000000003727080 ProgramData                    C:\ProgramData
    1000 explorer.exe         0x0000000003727080 ProgramFiles                   C:\Program Files
    1000 explorer.exe         0x0000000003727080 ProgramFiles(x86)              C:\Program Files (x86)
    1000 explorer.exe         0x0000000003727080 ProgramW6432                   C:\Program Files
    1000 explorer.exe         0x0000000003727080 PSModulePath                   C:\Windows\system32\WindowsPowerShell\v1.0\Modules\
    1000 explorer.exe         0x0000000003727080 PUBLIC                         C:\Users\Public
    1000 explorer.exe         0x0000000003727080 SESSIONNAME                    Console
    1000 explorer.exe         0x0000000003727080 SystemDrive                    C:
    1000 explorer.exe         0x0000000003727080 SystemRoot                     C:\Windows
    1000 explorer.exe         0x0000000003727080 TEMP                           C:\Users\SBA_AK\AppData\Local\Temp
    1000 explorer.exe         0x0000000003727080 TMP                            C:\Users\SBA_AK\AppData\Local\Temp
    1000 explorer.exe         0x0000000003727080 USERDOMAIN                     FORENWARMUP
    1000 explorer.exe         0x0000000003727080 USERNAME                       SBA_AK
    1000 explorer.exe         0x0000000003727080 USERPROFILE                    C:\Users\SBA_AK
    1000 explorer.exe         0x0000000003727080 windir                         C:\Windows
    1000 explorer.exe         0x0000000003727080 windows_tracing_flags          3
    1000 explorer.exe         0x0000000003727080 windows_tracing_logfile        C:\BVTBin\Tests\installpackage\csilogfile.log

$ volatility -f foren.raw  --profile=Win7SP1x64 hivelist
Volatility Foundation Volatility Framework 2.6
Virtual            Physical           Name
------------------ ------------------ ----
0xfffff8a000b0f410 0x000000002720d410 \??\C:\Windows\ServiceProfiles\LocalService\NTUSER.DAT
0xfffff8a000d00010 0x000000001ff75010 \??\C:\Windows\ServiceProfiles\NetworkService\NTUSER.DAT
0xfffff8a000f8b410 0x00000000175e8410 \??\C:\Windows\System32\config\COMPONENTS
0xfffff8a00145f010 0x0000000027d9b010 \SystemRoot\System32\Config\DEFAULT
0xfffff8a0014da410 0x00000000275c0410 \SystemRoot\System32\Config\SAM
0xfffff8a0033fe410 0x0000000069de6410 \??\C:\Users\SBA_AK\ntuser.dat
0xfffff8a0036e7010 0x0000000069188010 \??\C:\Users\SBA_AK\AppData\Local\Microsoft\Windows\UsrClass.dat
0xfffff8a0038fe280 0x0000000068390280 \??\C:\System Volume Information\Syscache.hve
0xfffff8a00000f010 0x000000002cfef010 [no name]
0xfffff8a000024010 0x000000002d07a010 \REGISTRY\MACHINE\SYSTEM
0xfffff8a000058010 0x000000002d3ae010 \REGISTRY\MACHINE\HARDWARE
0xfffff8a000846010 0x000000002a0e9010 \Device\HarddiskVolume1\Boot\BCD
0xfffff8a000873010 0x0000000013880010 \SystemRoot\System32\Config\SOFTWARE
0xfffff8a000ab8010 0x0000000027455010 \SystemRoot\System32\Config\SECURITY

$ volatility -f foren.raw  --profile=Win7SP1x64 hashdump -y 0xfffff8a000024010 -s 0xfffff8a0014da410 > hashes.txt
Volatility Foundation Volatility Framework 2.6

$ cat hashes.txt
Administrator:500:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
fwordCTF:1000:aad3b435b51404eeaad3b435b51404ee:a9fdfa038c4b75ebc76dc855dd74f0da:::
HomeGroupUser$:1002:aad3b435b51404eeaad3b435b51404ee:514fab8ac8174851bfc79d9a205a939f:::
SBA_AK:1004:aad3b435b51404eeaad3b435b51404ee:a9fdfa038c4b75ebc76dc855dd74f0da:::

SBA_AKユーザのハッシュ"a9fdfa038c4b75ebc76dc855dd74f0da"をCrackStationでクラックする。

password123
FwordCTF{FORENWARMUP_SBA_AK_password123}

NULL (Forensics)

バイナリエディタで見ると、シグネチャ部分とIHDRチャンクが壊れているので、まず以下を修正する。

\x69 -> \x89
ihdr -> IHDR

あと幅、高さが0になっているので、幅から総当たりで画像が表示されるのを探す。

import struct
import binascii

with open('NULL_mod', 'rb') as f:
    data = f.read()

head = data[:16]
tail = data[33:]

h = 512
for w in range(1, 1025):
    width = struct.pack('>I', w)
    height = struct.pack('>I', h)
    ihdr = 'IHDR' + width + height + data[24:29]
    crc = struct.pack('!l', binascii.crc32(ihdr))
    out = head + width + height + data[24:29]
    out += crc + tail

    fname = 'png/NULL_%04d.png' % w
    with open(fname, 'wb') as f:
        f.write(out)

幅は878とわかったので、これでフラグがわかるが、一応高さを変えて、CRCが一致するものを探す。

import struct
import binascii

with open('NULL_mod', 'rb') as f:
    data = f.read()

head = data[:16]
tail = data[33:]
real_crc = data[29:33]

w = 878
for h in range(1, 513):
    width = struct.pack('>I', w)
    height = struct.pack('>I', h)
    ihdr = 'IHDR' + width + height + data[24:29]
    crc = struct.pack('!l', binascii.crc32(ihdr))
    if crc == real_crc:
        out = head + width + height + data[24:29]
        out += crc + tail

        with open('flag.png', 'wb') as f:
            f.write(out)
        break

f:id:satou-y:20200911080618p:plain

FwordCTF{crc32_is_the_way}

One Part ! (Cryptography)

$ nc onepart.fword.wtf 4445

	Welcome to my secure Land !!! 
	Everything is in front of you !
	test it for me before publishing it 
		
you public pair : (27039764981309062625274898320208198235643402129311297263785776859702567126302222303738521740483786237227836456002390981734283009006700563362069542699483689586471105688808781640153941304591080040383895754868862710613679457405746983155013057546877276514113372108434147893247300672862804247578998741682187807110888306493721679533194719441701944588595026334355868149028690566150407046958439677301961584501192792882409106221411279970592183351437049913231763773630321987100804961438363763243479282784091714158649965751843237505118898648618229879476950971022131212202271865554015690669007601158309303245517015507325503019567, 65537)
Bonus information 
dp : 660952416188731114032555504620445492615410555198783725560501148434318958997557163596572558261630090859488182770978438064818967334816721872896552465974246586968024897417839477319093627169084177551568270282904313548871297791174366659815201519142629330432165141999305979854052687693462464094606979380005975305
Cipher : 20050018413065014291218623948713706488273506951753749286964735060394362464018065053239004000574937641345807278774383544916174889931360084129147350699072425229209853982959791054432412209761545569289714368676057061637904941432237677523141681154716706832054712909275365835497898557199143397983868562873307563650953724664427543578829650917394538014784718892332353421521082106207181405979433768385022977294969122617047013089017908368403008368196526581669187759119363437147804759592297951454337036091833814114553169671439550285871844410910807840472023880756524223164751118107949322391672329807758412471322944200191051798428

https://blog.csdn.net/hijklmnopq123/article/details/107145081を参考にn, e, dpからp, qを求め、復号する。

from Crypto.Util.number import *

n = 27039764981309062625274898320208198235643402129311297263785776859702567126302222303738521740483786237227836456002390981734283009006700563362069542699483689586471105688808781640153941304591080040383895754868862710613679457405746983155013057546877276514113372108434147893247300672862804247578998741682187807110888306493721679533194719441701944588595026334355868149028690566150407046958439677301961584501192792882409106221411279970592183351437049913231763773630321987100804961438363763243479282784091714158649965751843237505118898648618229879476950971022131212202271865554015690669007601158309303245517015507325503019567
e = 65537
dp = 660952416188731114032555504620445492615410555198783725560501148434318958997557163596572558261630090859488182770978438064818967334816721872896552465974246586968024897417839477319093627169084177551568270282904313548871297791174366659815201519142629330432165141999305979854052687693462464094606979380005975305
c = 20050018413065014291218623948713706488273506951753749286964735060394362464018065053239004000574937641345807278774383544916174889931360084129147350699072425229209853982959791054432412209761545569289714368676057061637904941432237677523141681154716706832054712909275365835497898557199143397983868562873307563650953724664427543578829650917394538014784718892332353421521082106207181405979433768385022977294969122617047013089017908368403008368196526581669187759119363437147804759592297951454337036091833814114553169671439550285871844410910807840472023880756524223164751118107949322391672329807758412471322944200191051798428

def solve(dp, n, e):
    for i in range(1, e):
        if ((e * dp - 1) % i) == 0:
            tmp_p = (e * dp - 1) / i + 1
            if n % tmp_p == 0:
                p = tmp_p
                q = n / p
                return p, q

p, q = solve(dp, n, e)
d = inverse(e, (p - 1) * (q - 1))
m = pow(c, d, n)
flag = long_to_bytes(m)
print flag
FwordCTF{i_knew_it_its_not_secure_as_i_thought}

Randomness (Cryptography)

p, a, b: ランダム64ビット整数
xをランダム64ビット整数とする。

X[0] = (a * x + b) % p
X[1] = (a * X[0] + b) % p
X[2] = (a * X[1] + b) % p
    :

outputはord(flag[i]) ^ X[i]

"FwordCTF{"から始まることからX[i]の最初の方はわかる。mod pで、以下のようになる。

X[2] - X[1] = a * (X[1] - X[0])
X[3] - X[2] = a * (X[2] - X[1]) = a**2 * (X[1] - X[0])
    :

(X[2] - X[1])**2 - (X[3] - X[2]) * (X[1] - X[0]) = 0 mod p

このことからわかる範囲で最大公約数からpを求める。pがわかれば、a, bを計算し、XOR鍵を算出できるので、フラグが復号できる。

from Crypto.Util.number import *
from functools import reduce

output = [6680465291011788243L, 5100570103593250421L, 5906808313299165060L, 1965917782737693358L, 9056785591048864624L, 1829758495155458576L, 6790868899161600055L, 1596515234863242823L, 1542626304251881891L, 8104506805098882719L, 1007224930233032567L, 3734079115803760073L, 7849173324645439452L, 8732100672289854567L, 5175836768003400781L, 1424151033239111460L, 1199105222454059911L, 1664215650827157105L, 9008386209424299800L, 484211781780518254L, 2512932525834758909L, 270126439443651096L, 3183206577049996011L, 3279047721488346724L, 3454276445316959481L, 2818682432513461896L, 1198230090827197024L, 6998819122186572678L, 9203565046169681246L, 2238598386754583423L, 467098371562174956L, 5653529053698720276L, 2015452976526330232L, 2551998512666399199L, 7069788985925185031L, 5960242873564733830L, 8674335448210427234L, 8831855692621741517L, 6943582577462564728L, 2159276184039111694L, 8688468346396385461L, 440650407436900405L, 6995840816131325250L, 4637034747767556143L, 3074066864500201630L, 3089580429060692934L, 2636919931902761401L, 5048459994558771200L, 6575450200614822046L, 666932631675155892L, 3355067815387388102L, 3494943856508019168L, 3208598838604422062L, 1651654978658074504L, 1031697828323732832L, 3522460087077276636L, 6871524519121580258L, 6523448658792083486L, 127306226106122213L, 147467006327822722L, 3241736541061054362L, 8781435214433157730L, 7267936298215752831L, 3411059229428517472L, 6597995245035183751L, 1256684894889830824L, 6272257692365676430L, 303437276610446361L, 8730871523914292433L, 6472487383860532571L, 5022165523149187811L, 4462701447753878703L, 1590013093628585660L, 4874224067795612706L]

pre_flag = 'FwordCTF{'

X = []
for i in range(len(pre_flag)):
    X.append(ord(pre_flag[i]) ^ output[i])

delta = [d1 - d0 for (d0, d1) in zip(X, X[1:])]
p_mul = [d0 * d2 - d1 * d1 for (d0, d1, d2) in zip(delta, delta[1:], delta[2:])]
p = reduce(GCD, p_mul)

a = (delta[1] * inverse(delta[0], p)) % p
b = (X[1] - a * X[0]) % p

print '[+] p =', p
print '[+] a =', a
print '[+] b =', b

flag = ''
X = X[0]
for i in range(len(output)):
    flag += chr(output[i] ^ X)
    X = (a * X + b) % p

print flag

実行結果は以下の通り。

[+] p = 9444729917070668893
[+] a = 7762244320486225184
[+] b = 731234830430177597
FwordCTF{LCG_easy_to_break!That_was_a_mistake_choosing_it_as_a_secure_way}
FwordCTF{LCG_easy_to_break!That_was_a_mistake_choosing_it_as_a_secure_way}

Weird RSA (Cryptography)

1文字ずつ暗号化しているが、eもわからないため復号するのは困難。長文になっているが文字種は31なので、調整しながら文字に変換し、quipqiupを使って復号していく。

import string

with open('encrypted', 'r') as f:
    n = int(f.readline())
    arr = eval(f.readline())

chars = string.lowercase + string.uppercase

tbl = {}
i = 0
for c in arr:
    if c == 122807939030811245186686213213868850447303361094887418429802328758871083280273648857856918935637132648632243184233539456656459739043437190716468530659433054053380009201788486772315058439741781541436263156772242972083577746222547181045630513749586717058856495432354539934699067011602866550637464982796912093925:
        tbl[c] = ' '
    elif c == 111932180905630654493095096998751315337993895388833160004035205358665150386315218560862289272752805766121221803672226162441143047831897169048560137369939605314367156571500174162927880529734495863569484107147545881268782484521789474896936578897185312219291010358781566096011433862394376273491164217263698796039:
        tbl[c] = '.'
    elif c == 22721408574029169941559271421580596463354509165085559818380584219610806054020395600401582603983198541895122046682436088370620955418228925678707479410682910787183872448016361565883789426941184841288326512093277969098312933014822934387432072254554865172436391757020769683818824706149869890219517158214360667121:
        tbl[c] = ','
    elif c == 11103712323084947367644009453488948685929911479783334272359497021552499331245181056574512375375010109816260980007845348445504036052179142571968217713928072401763654463899708284432083213717605057931047529100775985319501314022108448419604618502053221482140628305710736902065384556099657446407689798404501634859:
        tbl[c] = '('
    elif c == 2646067438947835044558655298997948344536252904197328865209740159995225103299363625784634898680910802118268396957771576806649232168642019224036788882331828238798357208476606867950952055712876439248426965116034587132739644870979899276335264481968682386393675554960790700454833479856256396502349851837228949191:
        tbl[c] = ')'
    elif c == 79098859484799315497438201884854356665762404985933961360965823759757565814432242150827072902796538903565668501723567047036581585142560327204520026652474025810567267834630257787821434248156015359884217808479487289818792639319776231987533832534441274127981919454962567578780520428942143126506679430744448149665:
        tbl[c] = ':'
    if c not in tbl:
        tbl[c] = chars[i]
        i += 1

msg = ''
for c in arr:
    msg += tbl[c]

print msg

記号のみを復号した結果は以下の通り。

abcdecfgh ifijhklk lk ekcm anb obciplfq keokrlrerlnf glstcbk. rtc qcfcbij lmci lk rn alfm rtc snsejib jcrrcbk lf rtc glstcbrcur ifm rbh rn bcsjigc rtcv oh rtc gnvvnf jcrrcbk lf rtc ekcm jifqeiqc. rtc irrigpcb ekeijjh gtcgpk knvc snkkloljlrlck ifm vipck knvc keokrlrerlnfk na jcrrcbk lf glstcbrcur. tc jnnpk anb snkklojc issciblfq wnbmk ifm oikcm nf rtir vipck vnbc keokrlrerlnfk. eklfq gnvsercbk, lr lk snkklojc rn rbh i jnr na gnvolfirlnfk lf bcjirlxc ktnbr rlvc. wbis rtc ajiq lf lrk anbvir : wcjjabcdecfghifijhklkbngpk. anb cuivsjc, la lf rtc ifijhycm glstcbrcur rtc vnkr snsejib jcrrcb lk u, nfc vih sbcmlgr rtir u bcsjigcm c nb n (nfc na rtc vnkr snsejib jcrrcbk lf cfqjlkt) abnv rtc sjilfrcur. lr lk ekcaej rn jnnp anb snsejib silbk na jcrrcbk nb cxcf rbh rn sbcmlgr knvc abcdecfr jnfqcb kcdecfgck na jcrrcbk nb wtnjc wnbmk. rtc lfrbemcb ijwihk rblck rn alfm kcdecfgck na jcrrcbk wtlgt ibc narcf ekcm lf rtc kcjcgrcm jifqeiqc.

quipqiupで復号すると、以下のようになる。

frequency analysis is used for breaking substitution ciphers. the general idea is to find the popular letters in the ciphertext and try to replace them by the common letters in the used language. the attacker usually checks some possibilities and makes some substitutions of letters in ciphertext. he looks for possible appearing words and based on that makes more substitutions. using computers, it is possible to try a lot of combinations in relative short time. wrap the flag in its format : wellfrequencyanalysisrocks. for example, if in the analyzed ciphertext the most popular letter is x, one may predict that x replaced e or o (one of the most popular letters in english) from the plaintext. it is useful to look for popular pairs of letters or even try to predict some frequent longer sequences of letters or whole words. the intruder always tries to find sequences of letters which are often used in the selected language.
FwordCTF{wellfrequencyanalysisrocks}