Skip to content

Commit 51b11de

Browse files
committed
Add a Django Upload examples
1 parent 54cc4d6 commit 51b11de

File tree

2 files changed

+57
-8
lines changed

2 files changed

+57
-8
lines changed

python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpackQuery.qll

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,10 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration {
5555
at = s.getObject() and at.getAttr() = "FILES" and source.asExpr() = s
5656
)
5757
or
58+
// Retrieve Django uploaded files
59+
// see HttpRequest.FILES: https://docs.djangoproject.com/en/4.1/ref/request-response/#django.http.HttpRequest.FILES
5860
exists(Node obj, AttrRead ar |
59-
ar.getAMethodCall("get").flowsTo(source) and
60-
ar.accesses(obj, "FILES")
61-
)
62-
or
63-
exists(Node obj, AttrRead ar |
64-
ar.getAMethodCall("getlist").flowsTo(source) and
61+
ar.getAMethodCall(["getlist", "get"]).flowsTo(source) and
6562
ar.accesses(obj, "FILES")
6663
)
6764
}
@@ -93,7 +90,21 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration {
9390
exists(MethodCallNode mc |
9491
nodeFrom = mc.getObject() and
9592
mc.getMethodName() = "read" and
96-
mc.flowsTo(nodeTo)
93+
nodeTo = mc
94+
)
95+
or
96+
// Open for access
97+
exists(MethodCallNode cn |
98+
nodeTo = cn.getObject() and
99+
cn.getMethodName() = "open" and
100+
cn.flowsTo(nodeFrom)
101+
)
102+
or
103+
// Write for access
104+
exists(MethodCallNode cn |
105+
nodeTo = cn.getObject() and
106+
cn.getMethodName() = "write" and
107+
nodeFrom = cn.getArg(0)
97108
)
98109
or
99110
// Accessing the name or raw content

python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,42 @@ def download_from_url():
8585
with open(tarpath, "wb") as f:
8686
f.write(response.raw.read())
8787

88-
shutil.unpack_archive(tarpath, base_dir) # $result=BAD
88+
shutil.unpack_archive(tarpath, base_dir) # $result=BAD
89+
90+
# the django upload functionality
91+
# see HttpRequest.FILES: https://docs.djangoproject.com/en/4.1/ref/request-response/#django.http.HttpRequest.FILES
92+
from django.shortcuts import render
93+
from django.core.files.storage import FileSystemStorage
94+
import shutil
95+
96+
def simple_upload(request):
97+
98+
base_dir = "/tmp/baase_dir"
99+
if request.method == 'POST':
100+
# Read uploaded files by chunks of data
101+
# see chunks(): https://docs.djangoproject.com/en/4.1/ref/files/uploads/#django.core.files.uploadedfile.UploadedFile.chunks
102+
savepath = os.path.join(base_dir, "tarball_compressed.tar.gz")
103+
with open(savepath, 'wb+') as wfile:
104+
for chunk in request.FILES["ufile1"].chunks():
105+
wfile.write(chunk)
106+
shutil.unpack_archive(savepath, base_dir) # $result=BAD
107+
108+
# Write in binary the uploaded tarball
109+
myfile = request.FILES.get("ufile1")
110+
file_path = os.path.join(base_dir, "tarball.tar")
111+
with file_path.open('wb') as f:
112+
f.write(myfile.read())
113+
shutil.unpack_archive(file_path, base_dir) # $result=BAD
114+
115+
# Save uploaded files using FileSystemStorage Django API
116+
# see FileSystemStorage: https://docs.djangoproject.com/en/4.1/ref/files/storage/#django.core.files.storage.FileSystemStorage
117+
for ufile in request.FILES.getlist():
118+
fs = FileSystemStorage()
119+
filename = fs.save(ufile.name, ufile)
120+
uploaded_file_path = fs.path(filename)
121+
shutil.unpack_archive(uploaded_file_path, base_dir) # $result=BAD
122+
123+
return render(request, 'simple_upload.html')
124+
125+
elif request.method == 'GET':
126+
return render(request, 'simple_upload.html')

0 commit comments

Comments
 (0)