Skip to content

Commit b7caca8

Browse files
authored
chore: reduce FPs in decode-and-execute by removing file write and network connection sinks (#1237)
Remove network connection and file write sinks from the obfuscation decode-and-execute Semgrep rules to reduce false positives. Signed-off-by: Carl Flottmann <[email protected]>
1 parent 289599f commit b7caca8

File tree

3 files changed

+268
-448
lines changed

3 files changed

+268
-448
lines changed

src/macaron/resources/pypi_malware_rules/obfuscation.yaml

Lines changed: 0 additions & 156 deletions
Original file line numberDiff line numberDiff line change
@@ -111,135 +111,6 @@ rules:
111111

112112
pattern-sinks:
113113
- pattern-either:
114-
# remote connection
115-
# using socket module
116-
- patterns:
117-
- pattern-either:
118-
- patterns:
119-
- pattern-either:
120-
- pattern-inside: |
121-
$SOC = socket.socket(...)
122-
...
123-
- pattern-inside: |
124-
with socket.socket(...) as $SOC:
125-
...
126-
- pattern-either:
127-
- pattern-inside: |
128-
$SOC.connect(...)
129-
...
130-
- pattern-inside: |
131-
$SOC.connect_ex(...)
132-
...
133-
- pattern-inside: |
134-
$SOC.bind(...)
135-
...
136-
# socket.socket and socket.connect in one call
137-
- pattern-inside: |
138-
$SOC = socket.create_connection(...)
139-
...
140-
- pattern-inside: |
141-
with socket.create_connection(...) as $SOC:
142-
...
143-
# socket.socket and socket.bind in one call
144-
- pattern-inside: |
145-
$SOC = socket.create_server(...)
146-
...
147-
- pattern-inside: |
148-
with socket.create_server(...) as $SOC:
149-
...
150-
- pattern-either:
151-
# Assume that .accept, .listen was called somewhere if needed
152-
- pattern: $SOC.send(...)
153-
- pattern: $SOC.recv(...)
154-
- pattern: $SOC.recvfrom(...)
155-
- pattern: $SOC.recvmsg(...)
156-
- pattern: $SOC.recvmsg_into(...)
157-
- pattern: $SOC.recvfrom_into(...)
158-
- pattern: $SOC.recv_into(...)
159-
- pattern: $SOC.sendall(...)
160-
- pattern: $SOC.sendto(...)
161-
- pattern: $SOC.sendmsg(...)
162-
- pattern: $SOC.sendmsg_afalg(...)
163-
- pattern: $SOC.sendfile(...)
164-
# using requests module
165-
- pattern: requests.get(...)
166-
- pattern: requests.post(...)
167-
- pattern: requests.put(...)
168-
- pattern: requests.delete(...)
169-
- pattern: requests.head(...)
170-
- pattern: requests.options(...)
171-
- pattern: requests.patch(...)
172-
- pattern: requests.Session(...).get(...)
173-
- pattern: requests.Session(...).delete(...)
174-
- pattern: requests.Session(...).head(...)
175-
- pattern: requests.Session(...).options(...)
176-
- pattern: requests.Session(...).patch(...)
177-
- pattern: requests.Session(...).post(...)
178-
- pattern: requests.Session(...).put(...)
179-
- pattern: requests.Session(...).request(...)
180-
- pattern: requests.Session(...).send(...)
181-
- pattern: requests.Request(...)
182-
# using urllib3 module
183-
- pattern: urllib3.request(...)
184-
# object creation here is included as decoded values may be passed as parameters
185-
- pattern: urllib3.PoolManager(...)
186-
- pattern: urllib3.PoolManager(...).request(...)
187-
- pattern: urllib3.PoolManager(...).request_encode_body(...)
188-
- pattern: urllib3.PoolManager(...).request_encode_url(...)
189-
- pattern: urllib3.PoolManager(...).urlopen(...)
190-
- pattern: urllib3.HTTPConnectionPool(...)
191-
- pattern: urllib3.HTTPConnectionPool(...).urlopen(...)
192-
- pattern: urllib3.HTTPConnectionPool(...).request(...)
193-
- pattern: urllib3.HTTPConnectionPool(...).request_encode_body(...)
194-
- pattern: urllib3.HTTPConnectionPool(...).request_encode_url(...)
195-
- pattern: urllib3.HTTPSConnectionPool(...)
196-
- pattern: urllib3.HTTPSConnectionPool(...).urlopen(...)
197-
- pattern: urllib3.HTTPSConnectionPool(...).request(...)
198-
- pattern: urllib3.HTTPSConnectionPool(...).request_encode_body(...)
199-
- pattern: urllib3.HTTPSConnectionPool(...).request_encode_url(...)
200-
- pattern: urllib3.HTTPConnection(...)
201-
- pattern: urllib3.HTTPConnection(...).request(...)
202-
- pattern: urllib3.HTTPConnection(...).request_chunked(...)
203-
- pattern: urllib3.HTTPSConnection(...)
204-
- pattern: urllib3.HTTPSConnection(...).request(...)
205-
- pattern: urllib3.HTTPSConnection(...).request_chunked(...)
206-
- pattern: urllib3.ProxyManager(...).urlopen(...)
207-
# using urllib
208-
- pattern: urllib.request(...)
209-
- pattern: urllib.request.urlopen(...)
210-
# using httpx
211-
- pattern: httpx.request(...)
212-
- pattern: httpx.get(...)
213-
- pattern: httpx.post(...)
214-
- pattern: httpx.put(...)
215-
- pattern: httpx.delete(...)
216-
- pattern: httpx.head(...)
217-
- pattern: httpx.options(...)
218-
- pattern: httpx.stream(...)
219-
- pattern: httpx.patch(...)
220-
- pattern: httpx.AsyncClient(...)
221-
- pattern: httpx.AsyncClient(...).request(...)
222-
- pattern: httpx.AsyncClient(...).get(...)
223-
- pattern: httpx.AsyncClient(...).post(...)
224-
- pattern: httpx.AsyncClient(...).put(...)
225-
- pattern: httpx.AsyncClient(...).delete(...)
226-
- pattern: httpx.AsyncClient(...).head(...)
227-
- pattern: httpx.AsyncClient(...).options(...)
228-
- pattern: httpx.AsyncClient(...).stream(...)
229-
- pattern: httpx.AsyncClient(...).patch(...)
230-
- pattern: httpx.AsyncClient(...).send(...)
231-
- pattern: httpx.Client(...)
232-
- pattern: httpx.Client(...).request(...)
233-
- pattern: httpx.Client(...).get(...)
234-
- pattern: httpx.Client(...).post(...)
235-
- pattern: httpx.Client(...).put(...)
236-
- pattern: httpx.Client(...).delete(...)
237-
- pattern: httpx.Client(...).head(...)
238-
- pattern: httpx.Client(...).options(...)
239-
- pattern: httpx.Client(...).stream(...)
240-
- pattern: httpx.Client(...).patch(...)
241-
- pattern: httpx.Client(...).send(...)
242-
243114
# process spawning
244115
# using subprocess module
245116
- pattern: subprocess.check_output(...)
@@ -285,33 +156,6 @@ rules:
285156
- pattern: __import__('builtins').exec(...)
286157
- pattern: __import__('builtins').eval(...)
287158

288-
# file write
289-
- patterns:
290-
- pattern-either:
291-
- pattern-inside: |
292-
with open(...) as $FILE:
293-
...
294-
- pattern-inside: |
295-
with builtins.open(...) as $FILE:
296-
...
297-
- pattern-inside: |
298-
with __import__('builtins').open(...) as $FILE:
299-
...
300-
- pattern-inside: |
301-
$FILE = open(...)
302-
...
303-
- pattern-inside: |
304-
$FILE = builtins.open(...)
305-
...
306-
- pattern-inside: |
307-
$FILE = __import__('builtins').open(...)
308-
...
309-
- pattern: $FILE.write(...)
310-
- pattern: os.write(...)
311-
- pattern: os.writev(...)
312-
- pattern: os.pwrite(...)
313-
- pattern: os.pwritev(...)
314-
315159
- id: obfuscation_excessive-spacing
316160
metadata:
317161
description: Detects the use of excessive spacing in code, which may indicate obfuscation or hidden code.

tests/malware_analyzer/pypi/resources/sourcecode_samples/obfuscation/decode_and_execute.py

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,6 @@ def marshal_flow():
3232
def marshal_inline_flow():
3333
exec(__import__('marshal').loads(b'\xe3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00@\x00\x00\x00s\x0c\x00\x00\x00e\x00d\x00\x83\x01\x01\x00d\x01S\x00)\x02z\x0cHello world!N)\x01\xda\x05print\xa9\x00r\x02\x00\x00\x00r\x02\x00\x00\x00\xfa\x08<string>\xda\x08<module>\x01\x00\x00\x00\xf3\x00\x00\x00\x00'))
3434

35-
def bytes_eval_to_soc_bind():
36-
import socket
37-
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as soc:
38-
soc.bind(__import__('builtins').eval(b'("127.0.0.1", 0)'.decode()))
39-
4035
def map_b64_to_request():
4136
import requests as req
4237

@@ -54,14 +49,5 @@ def zlib_ast_subprocess():
5449
# just decodes to ["echo", "Hello world!"]
5550
subprocess.Popen(literal_eval(zeeee.decompress(b'x\x9c\x8bVOM\xce\xc8W\xd7QP\xf7H\xcd\xc9\xc9W(\xcf/\xcaIQT\x8f\x05\x00]\xa0\x07\x9d').decode()))
5651

57-
def propagation_to_write():
58-
import os as e
59-
60-
# symbol propagations should detect assign of os as e to o and bytes to b and still trigger
61-
o = e
62-
b = bytes
63-
# just decodes to "Hello world!"
64-
contents = b.fromhex("48656C6C6F20776F726C6421")
65-
# just decodes to "some_path"
66-
file = o.open(''.join(chr(c) for c in [115, 111, 109, 101, 95, 112, 97, 116, 104]), o.O_RDWR)
67-
o.pwritev(file, contents, 0)
52+
def b64_reversed_decompressed_ioc():
53+
_ = lambda __ : __import__('zlib').decompress(__import__('base64').b64decode(__[::-1]));exec((_)(b'something_malicious_here'))

0 commit comments

Comments
 (0)