2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Pythonでprivateメソッドを外から呼ぶ方法

Last updated at Posted at 2022-12-08

はじめに

これは RICORA Advent Calendar 2022 9日目の記事です。

以前CTFに参加した際に解いたPythonのエクスプロイトの問題で, privateなメソッドをクラスの外から呼ぶ解法で解いたので, 調べて直してまとめました.

Pythonのclassにおけるprivateの振る舞い

まず, 次のようなコードで通常の振る舞いを確認します.

test.py
class Test:
    a = 1
    __a = 10

    def show(self):
        print(self.a)

    def __private_show(self):
        print(self.__a)

普通の関数および変数は問題なく呼び出すことができます.

テストコード
test = Test()

print(test.a)
test.show()

# 1
# 1

アンダーバーを2つつけたフィールドおよび関数はprivateになるので, このような参照は行うことができません.

テストコード
print(test.__a)
test.__private_show()

# Traceback (most recent call last):
#   File "c:\Users\***\Documents\py\advent\a.py", line 17, in <module>
#     print(test.__a)
# AttributeError: 'Test' object has no attribute '__a' 

特殊属性, 特殊メソッドについて

これは __main____name__ などのことです. この2つはグローバルから参照することができたりしますが, classにおいても存在してます.
先ほどのTestクラスで試してみると

print(Test.__dict__.keys())

# dict_keys(['__module__', 'a', '_Test__a', 'show', '_Test__private_show', '__dict__', '__weakref__', '__doc__'])

このように, classの持つ名前空間にアクセスすることができます.

privateへのアクセス

これを使えば次のようにprivateなパラメータに対してもアクセスできてしまいます.

print(Test.__dict__["a"]) 
# 1
print(Test.__dict__["_Test__a"])
# 10
Test.__dict__["show"](Test)
# 1
Test.__dict__["_Test__private_show"](Test)
# 10

この方法を用いたCTFの問題では, evalに任意の文字を送ることができたので, この例のようにアクセスし, flagを入手しました.

追記

アクセスする際に参照した__dict__ですが, 公式ドキュメントによると

カスタムクラス型は通常、クラス定義 (クラス定義 参照) で生成されます。クラスは辞書オブジェクトで実装された名前空間を持っています。クラス属性の参照は、この辞書に対する探索 (lookup) に翻訳されます。例えば、 C.x は C.__dict__["x"] に翻訳されます (ただし、属性参照の意味を変えられる幾つかのフックがあります)。

ということなので, 次のように呼ぶこともできます.

print(Test._Test__a);
# 10
Test._Test__private_show(Test)
# 10

インスタンスからのアクセス

インスタンスからも同様にアクセスすることができます.

print(Test().show())
# 1

object.__new__(Test).show()
# 1

Test()._Test__private_show()
# 10

object.__new__(Test)._Test__private_show()
# 10

おわりに

最近pythonの仕様を突いたエクスプロイトの問題をよく見かけるので, 備忘録としてこの記事を書きました.
このジャンルの問題は毎回頭を悩ませる反面, 非常に面白くもあるのでCTFで見かけた際には積極的に解きに行こうと思います.

参考サイト

編集履歴

2022/12/09 __dict__について追記, インスタンスからの呼び出しについて訂正

2
0
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?