これは、セキュリティ上の脆弱性があると思われる 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