2

これは、セキュリティ上の脆弱性があると思われる JSON メッセージの送信に基づく非常に単純なシステムです。JSONオブジェクトを受け取り、それらに作用するPythonサーバー(標準ライブラリに含まれるJSONモジュールを使用)があります。取得した場合は{"req": "ping"}、単純に を返します{"resp": "pong"}。また、ボリュームを設定するためのコマンドと、管理者パスワードを変更するためのコマンドもあります。管理者は任意の JSON をこのサーバーに送信できます。ここにあります(server.py):

import json
import sys

def change_admin_password(p): pass # empty for test
def set_volume(v): pass # empty for test

def handle(js):
    if (js["req"] == "ping"):
        return {"resp": "pong"}
    if (js["req"] == "change admin password"):
        change_admin_password(js["args"]["password"])
        return {"resp": "ok"}
    if (js["req"] == "set volume"):
        set_volume(int(js["args"]["volume"]))
        return {"resp": "ok"}

print handle(json.load(sys.stdin))

stdin からコマンドを読み取り、処理します。別のスクリプトは、JSON オブジェクトをネットワーク ソケットから読み取り、このスクリプトに渡します。

他のユーザーは、 libjsonを使用して C++ で記述されたプロキシを通過する必要があります。管理者権限が必要なリクエストをブロックするだけです。たとえば、ユーザーが管理者パスワードを変更しようとすると、プロキシはコマンドを拒否します。

$ echo '{"req": "change admin password", "args": {"password":"new"}}' | ./proxy 
echo $?
1

コードは次のとおりです (proxy.cpp):

#include "libjson.h"
using namespace std;
int main() {
    string json((istreambuf_iterator<char>(cin)), istreambuf_iterator<char>());
    JSONNode n = libjson::parse(json);
    string req = n.at("req").as_string();
    if (req == "change admin password") {
        return 1;
    }
    cout << n.write();
}

プロキシを使用するには、ソケットを管理するメイン スクリプトがプロキシを介してデータをパイプし、そのデータを Python サーバーに出力します。

$ echo '{"req": "ping"}' | ./proxy | python server.py
{'resp': 'pong'}
$ echo '{"req": "set volume", "args": {"volume": 50}}' | ./proxy | python server.py 
{'resp': 'ok'}

また、ユーザーが制限されたコマンドを実行しようとすると、期待どおりに失敗します。

$ echo '{"req": "change admin password", "args": {"password": "new"}}' | ./proxy | python server.py 
Traceback (most recent call last):
  File "server.py", line 17, in <module>
[...]

しかし、何らかの理由で、「req」キーが JSON に 2 回ある場合 (違法ではないでしょうか?)、管理者以外のユーザーが管理者パスワードを変更できます。

$ echo '{"req": "nothing", "req": "change admin password", "args": {"password": "new"}}' | ./proxy | python server.py 
{'resp': 'ok'}

なんで?


Mike McMahon の回避策を試す:

回避策として使用JSONNode.findしてみましたが、機能していないようです。

すべての要素を繰り返してみました:

#include "libjson.h"
using namespace std;
int main() {
    string json((istreambuf_iterator<char>(cin)), istreambuf_iterator<char>());
    JSONNode n = libjson::parse(json);
    for (JSONNode::json_iterator it = n.begin(); it != n.end(); it++) {
        cout << "found one: " << it->at("x").as_string() << endl;
    }
}

これは機能します:

$ g++ proxy.cpp libjson.a  -o proxy && ./proxy
In file included from libjson.h:4:0,
                 from proxy.cpp:1:
_internal/Source/JSONDefs.h:157:6: warning: #warning , Release build of libjson, but NDEBUG is not on [-Wcpp]
{"a": {"x": 1}, "b": {"x": 2}}
found one: 1
found one: 2

JSONが無効な場合、セグメンテーション違反を除いて? イテレータを間違って使用していますか?

$ echo '{"a": {"x": 1}, {"b": {"x": 2}}' | ./proxy 
found one: 1
Segmentation fault

を次のように置き換えましn.begin()n.find("y")

#include "libjson.h"
using namespace std;
int main() {
    string json((istreambuf_iterator<char>(cin)), istreambuf_iterator<char>());
    JSONNode n = libjson::parse(json);
    for (JSONNode::json_iterator it = n.find("y"); it != n.end(); it++) {
        cout << "found one: " << it->at("x").as_string() << endl;
    }
}

まったく機能しません。イテレータを間違って使用していますか?

g++ proxy.cpp libjson.a  -o proxy && ./proxy
In file included from libjson.h:4:0,
                 from proxy.cpp:1:
_internal/Source/JSONDefs.h:157:6: warning: #warning , Release build of libjson, but NDEBUG is not on [-Wcpp]
{"y": {"x": 1}}
Segmentation fault

回避策の別の試み:

#include "libjson.h"
using namespace std;
int main() {
    string json((istreambuf_iterator<char>(cin)), istreambuf_iterator<char>());
    JSONNode n = libjson::parse(json);
    for (JSONNode::json_iterator it = n.begin(); it != n.end(); it++) {
        if (it->name() == "req" && it->as_string() == "change admin password")
        {
            cout << "found one " << endl;
        }
    }
}

できます!

$ echo '{"req": "change admin password"}' | ./proxy
found one 
$ echo '{"req": "x", "req": "change admin password"}' | ./proxy
found one 
$ echo '{"req": "change admin password", "req": "x"}' | ./proxy
found one 

しかし、まだ無効な JSON 入力でセグメンテーション違反が発生しますか?

$ echo '{"req": "x", {"req": "x"}' | ./proxy
Segmentation fault
4

1 に答える 1