mirror of
https://github.com/github/codeql.git
synced 2026-04-30 19:26:02 +02:00
Merge pull request #9108 from RasmusWL/promote-pam
Python: Promote `py/pam-auth-bypass`
This commit is contained in:
@@ -1,49 +0,0 @@
|
||||
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>
|
||||
Using only a call to
|
||||
<code>pam_authenticate</code>
|
||||
to check the validity of a login can lead to authorization bypass vulnerabilities.
|
||||
</p>
|
||||
<p>
|
||||
A
|
||||
<code>pam_authenticate</code>
|
||||
only verifies the credentials of a user. It does not check if a user has an appropriate authorization to actually login. This means a user with a expired login or a password can still access the system.
|
||||
</p>
|
||||
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>
|
||||
A call to
|
||||
<code>pam_authenticate</code>
|
||||
should be followed by a call to
|
||||
<code>pam_acct_mgmt</code>
|
||||
to check if a user is allowed to login.
|
||||
</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>
|
||||
In the following example, the code only checks the credentials of a user. Hence, in this case, a user expired with expired creds can still login. This can be verified by creating a new user account, expiring it with
|
||||
<code>chage -E0 `username` </code>
|
||||
and then trying to log in.
|
||||
</p>
|
||||
<sample src="PamAuthorizationBad.py" />
|
||||
|
||||
<p>
|
||||
This can be avoided by calling
|
||||
<code>pam_acct_mgmt</code>
|
||||
call to verify access as has been done in the snippet shown below.
|
||||
</p>
|
||||
<sample src="PamAuthorizationGood.py" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>
|
||||
Man-Page:
|
||||
<a href="https://man7.org/linux/man-pages/man3/pam_acct_mgmt.3.html">pam_acct_mgmt</a>
|
||||
</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -1,36 +0,0 @@
|
||||
/**
|
||||
* @name Authorization bypass due to incorrect usage of PAM
|
||||
* @description Using only the `pam_authenticate` call to check the validity of a login can lead to a authorization bypass.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision high
|
||||
* @id py/pam-auth-bypass
|
||||
* @tags security
|
||||
* external/cwe/cwe-285
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.ApiGraphs
|
||||
import experimental.semmle.python.Concepts
|
||||
import semmle.python.dataflow.new.TaintTracking
|
||||
|
||||
API::Node libPam() {
|
||||
exists(API::CallNode findLibCall, API::CallNode cdllCall |
|
||||
findLibCall = API::moduleImport("ctypes").getMember("util").getMember("find_library").getACall() and
|
||||
findLibCall.getParameter(0).getAValueReachingRhs().asExpr().(StrConst).getText() = "pam" and
|
||||
cdllCall = API::moduleImport("ctypes").getMember("CDLL").getACall() and
|
||||
cdllCall.getParameter(0).getAValueReachingRhs() = findLibCall
|
||||
|
|
||||
result = cdllCall.getReturn()
|
||||
)
|
||||
}
|
||||
|
||||
from API::CallNode authenticateCall, DataFlow::Node handle
|
||||
where
|
||||
authenticateCall = libPam().getMember("pam_authenticate").getACall() and
|
||||
handle = authenticateCall.getArg(0) and
|
||||
not exists(API::CallNode acctMgmtCall |
|
||||
acctMgmtCall = libPam().getMember("pam_acct_mgmt").getACall() and
|
||||
DataFlow::localFlow(handle, acctMgmtCall.getArg(0))
|
||||
)
|
||||
select authenticateCall, "This PAM authentication call may be lead to an authorization bypass."
|
||||
@@ -1,13 +0,0 @@
|
||||
def authenticate(self, username, password, service='login', encoding='utf-8', resetcreds=True):
|
||||
libpam = CDLL(find_library("pam"))
|
||||
pam_authenticate = libpam.pam_authenticate
|
||||
pam_authenticate.restype = c_int
|
||||
pam_authenticate.argtypes = [PamHandle, c_int]
|
||||
|
||||
|
||||
handle = PamHandle()
|
||||
conv = PamConv(my_conv, 0)
|
||||
retval = pam_start(service, username, byref(conv), byref(handle))
|
||||
|
||||
retval = pam_authenticate(handle, 0)
|
||||
return retval == 0
|
||||
@@ -1,17 +0,0 @@
|
||||
def authenticate(self, username, password, service='login', encoding='utf-8', resetcreds=True):
|
||||
libpam = CDLL(find_library("pam"))
|
||||
pam_authenticate = libpam.pam_authenticate
|
||||
pam_acct_mgmt = libpam.pam_acct_mgmt
|
||||
pam_authenticate.restype = c_int
|
||||
pam_authenticate.argtypes = [PamHandle, c_int]
|
||||
pam_acct_mgmt.restype = c_int
|
||||
pam_acct_mgmt.argtypes = [PamHandle, c_int]
|
||||
|
||||
handle = PamHandle()
|
||||
conv = PamConv(my_conv, 0)
|
||||
retval = pam_start(service, username, byref(conv), byref(handle))
|
||||
|
||||
retval = pam_authenticate(handle, 0)
|
||||
if retval == 0:
|
||||
retval = pam_acct_mgmt(handle, 0)
|
||||
return retval == 0
|
||||
Reference in New Issue
Block a user