Skip to content

Commit 785dc1a

Browse files
author
Porcupiney Hairs
committed
Include changes from review
1 parent 9203304 commit 785dc1a

File tree

6 files changed

+78
-235
lines changed

6 files changed

+78
-235
lines changed

python/ql/src/experimental/Security/CWE-285/PamAuthorization.ql

Lines changed: 17 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -13,46 +13,24 @@ import semmle.python.ApiGraphs
1313
import experimental.semmle.python.Concepts
1414
import semmle.python.dataflow.new.TaintTracking
1515

16-
private class LibPam extends API::Node {
17-
LibPam() {
18-
exists(
19-
API::Node cdll, API::Node find_library, API::Node libpam, API::CallNode cdll_call,
20-
API::CallNode find_lib_call, StrConst str
21-
|
22-
API::moduleImport("ctypes").getMember("CDLL") = cdll and
23-
find_library = API::moduleImport("ctypes.util").getMember("find_library") and
24-
cdll_call = cdll.getACall() and
25-
find_lib_call = find_library.getACall() and
26-
DataFlow::localFlow(DataFlow::exprNode(str), find_lib_call.getArg(0)) and
27-
str.getText() = "pam" and
28-
cdll_call.getArg(0) = find_lib_call and
29-
libpam = cdll_call.getReturn()
30-
|
31-
libpam = this
32-
)
33-
}
34-
35-
override string toString() { result = "libpam" }
36-
}
37-
38-
class PamAuthCall extends API::Node {
39-
PamAuthCall() { exists(LibPam pam | pam.getMember("pam_authenticate") = this) }
40-
41-
override string toString() { result = "pam_authenticate" }
42-
}
43-
44-
class PamActMgt extends API::Node {
45-
PamActMgt() { exists(LibPam pam | pam.getMember("pam_acct_mgmt") = this) }
46-
47-
override string toString() { result = "pam_acct_mgmt" }
16+
API::Node libPam() {
17+
exists(API::CallNode findLibCall, API::CallNode cdllCall, StrConst str |
18+
findLibCall = API::moduleImport("ctypes.util").getMember("find_library").getACall() and
19+
cdllCall = API::moduleImport("ctypes").getMember("CDLL").getACall() and
20+
DataFlow::localFlow(DataFlow::exprNode(str), findLibCall.getArg(0)) and
21+
str.getText() = "pam" and
22+
cdllCall.getArg(0) = findLibCall
23+
|
24+
result = cdllCall.getReturn()
25+
)
4826
}
4927

50-
from PamAuthCall p, API::CallNode u, Expr handle
28+
from API::CallNode authenticateCall, DataFlow::Node handle
5129
where
52-
u = p.getACall() and
53-
handle = u.asExpr().(Call).getArg(0) and
54-
not exists(PamActMgt pam |
55-
DataFlow::localFlow(DataFlow::exprNode(handle),
56-
DataFlow::exprNode(pam.getACall().asExpr().(Call).getArg(0)))
30+
authenticateCall = libPam().getMember("pam_authenticate").getACall() and
31+
handle = authenticateCall.getArg(0) and
32+
not exists(API::CallNode acctMgmtCall |
33+
acctMgmtCall = libPam().getMember("pam_acct_mgmt").getACall() and
34+
DataFlow::localFlow(handle, acctMgmtCall.getArg(0))
5735
)
58-
select u, "This PAM authentication call may be lead to an authorization bypass."
36+
select authenticateCall, "This PAM authentication call may be lead to an authorization bypass."

python/ql/src/experimental/Security/CWE-285/PamAuthorizationBad.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
def authenticate(self, username, password, service='login', encoding='utf-8', resetcreds=True):
22
libpam = CDLL(find_library("pam"))
33
pam_authenticate = libpam.pam_authenticate
4-
pam_acct_mgmt = libpam.pam_acct_mgmt
54
pam_authenticate.restype = c_int
65
pam_authenticate.argtypes = [PamHandle, c_int]
7-
pam_acct_mgmt.restype = c_int
8-
pam_acct_mgmt.argtypes = [PamHandle, c_int]
6+
97

108
handle = PamHandle()
119
conv = PamConv(my_conv, 0)
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
| bad.py:92:18:92:44 | ControlFlowNode for pam_authenticate() | This PAM authentication call may be lead to an authorization bypass. |
1+
| pam_test.py:44:18:44:44 | ControlFlowNode for pam_authenticate() | This PAM authentication call may be lead to an authorization bypass. |

python/ql/test/experimental/query-tests/Security/CWE-285/bad.py

Lines changed: 0 additions & 95 deletions
This file was deleted.

python/ql/test/experimental/query-tests/Security/CWE-285/good.py

Lines changed: 0 additions & 97 deletions
This file was deleted.
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
from ctypes import CDLL, POINTER, Structure, byref
2+
from ctypes import c_char_p, c_int
3+
from ctypes.util import find_library
4+
5+
6+
class PamHandle(Structure):
7+
pass
8+
9+
10+
class PamMessage(Structure):
11+
pass
12+
13+
14+
class PamResponse(Structure):
15+
pass
16+
17+
18+
class PamConv(Structure):
19+
pass
20+
21+
22+
libpam = CDLL(find_library("pam"))
23+
24+
pam_start = libpam.pam_start
25+
pam_start.restype = c_int
26+
pam_start.argtypes = [c_char_p, c_char_p, POINTER(PamConv), POINTER(PamHandle)]
27+
28+
pam_authenticate = libpam.pam_authenticate
29+
pam_authenticate.restype = c_int
30+
pam_authenticate.argtypes = [PamHandle, c_int]
31+
32+
pam_acct_mgmt = libpam.pam_acct_mgmt
33+
pam_acct_mgmt.restype = c_int
34+
pam_acct_mgmt.argtypes = [PamHandle, c_int]
35+
36+
37+
class pam():
38+
39+
def authenticate_bad(self, username, service='login'):
40+
handle = PamHandle()
41+
conv = PamConv(None, 0)
42+
retval = pam_start(service, username, byref(conv), byref(handle))
43+
44+
retval = pam_authenticate(handle, 0)
45+
auth_success = retval == 0
46+
47+
return auth_success
48+
49+
def authenticate_good(self, username, service='login'):
50+
handle = PamHandle()
51+
conv = PamConv(None, 0)
52+
retval = pam_start(service, username, byref(conv), byref(handle))
53+
54+
retval = pam_authenticate(handle, 0)
55+
if retval == 0:
56+
retval = pam_acct_mgmt(handle, 0)
57+
auth_success = retval == 0
58+
59+
return auth_success

0 commit comments

Comments
 (0)