跳到主要内容

🥷 OffSec CTF Writeup体验

因为上课要求要打一道 CTF 以及写一个 writeup, 所以在 ctftime 首页上看了几个正在进行的 CTF, 看到这个里的这道题.

📝 题目

Perhaps You Can

550d0d0a00000000b7e8566370030000e300000000000000000000000000000000080000004000000073300200006500640083015a0165026501830164016b02731c650364028301010065046501a005a100830164036b02733465036402830101006501640464058502190064066b02734c650364028301010065016407190064086b027360650364028301010065066501640919008301640a1800650665016405190083016b02738465036402830101006501640b190065076508650965066501640c19008301830164046404640785031900830183016b0273b6650364028301010065066501640b19008301640d180065066501640d190083016b0273da650364028301010065066501640e190083015a0a65066501640f190083015a0b650a650b170064106b02900173086503640283010100650c650a650b830264116b0090017320650364028301010065016412641385021900a005a100a00da10064146b029001734265036402830101006501641319006501641519006b029001735c65036402830101006501641519006501641619006b029001737665036402830101006506650164171900830165066501641819008301140064196b029001739c650364028301010065066501641a1900830165066501641b19008301140065066501641c190083011400641d6b02900173ce6503640283010100650e641ea00f6510641f64208400650164216422850219008302a10183015a116511a012a1000100641ea00f6511a10164236b029002730e650364028301010065016424190064256b0290027324650364028301010065136426830101006404530029277a07696e7075743e20e926000000e90100000069d20d00004ee9060000007a0655444354467be9fffffffffa017de905000000e902000000e907000000e903000000e909000000e908000000e90a000000e9eb000000e977000000e90b000000e9180000005a1a3333356636323333363536653566363237393734373433333665e91b000000e91f000000e919000000e91a00000069522e0000e91c000000e91d000000e91e0000006960630900da0063010000000000000000000000010000000300000043000000730c000000740074017c0083018301530029014e2902da03737472da036f72642901da0178a900721c000000fa087472796d652e7079da083c6c616d6264613e20000000f300000000721e000000e920000000e9250000005a0e3030303131313131313132353537e922000000da01347a07596f752077696e2914da05696e707574da03746d70da036c656eda0465786974da0373756dda06656e636f6465721a000000da03636872da03696e747219000000721b000000da0179da036d6178da03686578da046c697374da046a6f696eda036d6170da027979da04736f7274da057072696e74721c000000721c000000721c000000721d000000da083c6d6f64756c653e01000000734a00000008010c01080110010801100108010c0108011c0108012a0108011c0108010c010c010e010801100108011a01080112010801120108011e0108012a01080120010801100108010e010801

🧐 答案

拿到数字后, 观察即可知道, 这是一个十六进制的字符串, 于是放到 CyberChef 上, 选择 From Hex, 尝试获取更多信息.

于是我们可以从 output 中看到很多代码关键字, 但是没有办法确定是什么语言, 可能大概率是 python.

之后我们再回到 input 中, 来敲定代码的语言. 我们通过搜索前六位的前缀 550d0d0a, 可以从这个 magic number 中知道文件是 .pyc.

然后我们再通过脚本将 hex string 转换为 binary compiler pyc 文件.

import binascii

hexString = "550d0d0a......"
binary = binascii.a2b_hex(c)

file = open('binary.pyc','wb')
file.write(binary)

得到 binary.pyc 的文件后, 我们可以使用 uncompyle6 或者 PyC decompiler 来反编译这个二进制文件, 得到 .py 的源码.

# uncompyle6 version 3.5.0
# Python bytecode 3.8 (3413)
# Decompiled from: Python 2.7.5 (default, Nov 16 2020, 22:23:17)
# [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)]
# Embedded file name: tryme.py
# Size of source mod 2**32: 880 bytes
tmp = input('input> ')
if not len(tmp) == 38:
exit(1)
if not sum(tmp.encode()) == 3538:
exit(1)
if not tmp[:6] == 'UDCTF{':
exit(1)
if not tmp[(-1)] == '}':
exit(1)
if not ord(tmp[5]) - 2 == ord(tmp[6]):
exit(1)
if not tmp[7] == chr(int(str(ord(tmp[3]))[::-1])):
exit(1)
if not ord(tmp[7]) - 9 == ord(tmp[9]):
exit(1)
x = ord(tmp[8])
y = ord(tmp[10])
if not x + y == 235:
exit(1)
if not max(x, y) < 119:
exit(1)
if not tmp[11:24].encode().hex() == '335f6233656e5f62797474336e':
exit(1)
if not tmp[24] == tmp[27]:
exit(1)
if not tmp[27] == tmp[31]:
exit(1)
if not ord(tmp[25]) * ord(tmp[26]) == 11858:
exit(1)
if not ord(tmp[28]) * ord(tmp[29]) * ord(tmp[30]) == 615264:
exit(1)
yy = list(''.join(map(lambda x: str(ord(x)), tmp[32:37])))
yy.sort()
if not ''.join(yy) == '00011111112557':
exit(1)
if not tmp[34] == '4':
exit(1)
print('You win')

于是我们可以对这个代码进行分析, 得到 flag:

  • 对每个判断进行逐步分析, "翻译" 为 py 代码, 直接得到大部份的 flag.
  • 对 flag 的语义进行猜测, 如最后的 sn4ke, 在最后一个判断揭示中间字符为 4 后就可以结合前面的内容猜出这个词.
import binascii
flag = 'U D C T F {'.split() + ['*'] * (38 - 6)
flag[6] = chr(ord(flag[5]) - 2)
flag[7] = chr(int(str(ord(flag[3]))[::-1]))
flag[9] = chr(ord(flag[7]) - 9)
flag[-1] = '}'
flag[34] = '4'
flag[8] = 'u'
flag[10] = 'v'
flag_0 = str(binascii.a2b_hex('335f6233656e5f62797474336e'))[2:-1]
flag_1 = ''.join(flag)[:11] + flag_0
flag[25] = 'y'
flag[26] = 'b'
flag[28] = 't'
flag[29] = 'f'
flag[30] = 'h'
flag_2 = '_'+'b'+'y'+'_'+'t'+'h'+'3' + '_'
print(flag_1 + flag_2 + 'sn4ke}')

🚩 Flag

UDCTF{y0u'v3_b3en_bytt3n_by_th3_sn4ke}