NFsec Logo

Szukanie sekretów w plikach kodu bajtowego języka Python

29/09/2020 w Pen Test Brak komentarzy.  (artykuł nr 749, ilość słów: 577)

K

iedy wykonujemy program Python to w tle wykonuje się najpierw kompilacja kodu źródłowego (instrukcje znajdujące się w danym pliku .py) do formatu zwanego jako kod bajtowy. Kompilacja to proces tłumaczenia kodu na inny format, a w tym wypadku kod bajtowy jest niskopoziomową, niezależną od platformy reprezentacją kodu źródłowego. Język programowania Python przekłada każdą z instrukcji źródłowych na grupę instrukcji kodu bajtowego poprzez podzielenie ich na pojedyncze kroki. Proces przekładania kodu źródłowego na kod bajtowy odbywa się z myślą o szybkości wykonania – kod bajtowy może działać o wiele szybciej od oryginalnych instrukcji z kodu źródłowego zawartego w pliku tekstowym.

Jeżeli uruchomiony program Pythona ma uprawnienia do zapisu na naszym komputerze to kod bajtowy zostanie zapisany w pliku z rozszerzeniem .pyc. W wersji języka Python niższych niż 3.2, pliki takie pojawiają się po uruchomieniu programu obok plików źródłowych (z rozszerzeniem .py) w tym samym katalogu. Na przykład:

-rw-r--r--@  1 patryk.krawaczynski  staff       5515 Sep 29 21:04 settings.py
-rw-r--r--@  1 patryk.krawaczynski  staff       2474 Sep 29 21:00 settings.pyc

W wersji 3.2 i nowszych zapis plików kodu bajtowego przeniesiono do podkatalogu o nazwie __pycache__ (znajdującym się w katalogu z plikami źródłowymi), nadając im nazwy identyfikujące wersję Pythona, przy użyciu której zostały utworzone (np. secrets.cpython-37.pyc). W ten sposób podkatalog __pycache pomaga unikać nieporządku, a nowa konwencja nazewnictwa plików kodu bajtowego uniemożliwia różnym wersjom języka Python (jeśli mamy zainstalowanych kilka w systemie) wzajemne nadpisywanie zapisanego kodu bajtowego.

Powszechną praktyką w rozwijających się projektach Python jest również przechowywanie różnego rodzaju konfiguracji, kluczy, haseł i innych wrażliwych danych w plikach źródłowych np.: secrets.py, config.py lub settings.py. Zapewnia to dobre oddzielenie sekretów i kodu źródłowego – w dodatku pliki takie wczytuje się za pomocą wbudowanego importu języka i nie trzeba zajmować się operacjami wejścia / wyjścia dla innych formatów typu YAML, czy JSON.

O ile takie wrażliwe pliki często są dodawane do wykluczeń (np. .gitignore), aby nie znalazły się w systemach kontroli wersji to początkujący programiści zdają się zapominać o potencjalnym zagrożeniu wynikającym z tworzenia plików kodu bajtowego, gdzie ich sekrety w skompilowanej formie i tak lądują w repozytorium. Jeśli przeszukamy sobie serwis GitHub pod kątem różnych plików będziemy mogli poznać skalę tego zjawiska:

filename:apikey.pyc
filename:secret.pyc
filename:secrets.pyc
filename:secrets.cpython-37.pyc
filename:secrets.cpython-38.pyc
filename:config.pyc
filename:settings.pyc

Wyniki najlepiej posortować po ostatnio zaindeksowanych plikach (Sort: Recently indexed). Posiadając już ściągnięty plik, który podejrzewamy o przechowywanie wrażliwych danych – możemy poddać go procesowi dekompilacji – czyli odwrócić proces kompilacji – kod bajtowy przekształcić do kodu źródłowego. Pomóc nam w tym może narzędzie uncompyle6 (obsługuje wersję Python od 1.0 do 3.8):

agresor@stardust:~$ uncompyle6 secrets.cpython-37\ \(1\).pyc
# uncompyle6 version 3.7.4
# Python bytecode 3.7 (3394)
# Decompiled from: Python 3.8.2 (v3.8.2:7b3ab5921f, Feb 24 2020, 17:52:18)
# [Clang 6.0 (clang-600.0.57)]
# Embedded file name: /Users/n******s/Library/CloudDocs/Documents/tinderbot/secrets.py
# Compiled at: 2020-08-08 12:15:30
# Size of source mod 2**32: 80 bytes
username = 'n************l@googlemail.com'
password = 'r**********************t'
# okay decompiling secrets.cpython-37 (1).pyc

Podsumowanie:

Nawet doświadczonym programistom zdarza się popełnić błąd i wypchnąć wrażliwe pliki do repozytorium. Szczególnie, że wiele edytorów IDE ukrywa specjalne foldery i pliki w drzewie kodu źródłowego, aby uniknąć zaśmiecania ekranu. W ten sposób łatwo zapomnieć lub zorientować się, że pliki takie w ogóle istnieją. Unikanie tego typu wypadków wymaga używania dobrych plików .gitignore lub średniozaawansowanej wiedzy na temat elementów git (np. pre-receive sprawdzający wszystkie pliki *.pyc) i języka Python.

Więcej informacji: Finding secrets by decompiling Python bytecode in public repositories

Kategorie K a t e g o r i e : Pen Test

Tagi T a g i : , , , , , , , , ,

Komentowanie tego wpisu jest zablokowane.