Re: [sqlite] Authorizer bypass "vulnerability"

2017-04-13 Thread Richard Hipp
On 4/13/17, Keith Medcalf  wrote:
>
> So in the case of
> SQLite just using the standard shell compiled without authorization hooks in
> place is sufficient to do what you will to the database

Yes.  The sqlite3_set_authorizer() feature is designed to allow a
restricted subset of SQL to be used in web-applications where the
remote user does not have access to the original database.  For
example, in Fossil (https://www.fossil-scm.org/) it is possible to
allow anonymous users to enter SQL to query bug reports.  But we want
to prevent the anonymous users from access sensitive data, such as
user passwords.  Hence:
https://www.fossil-scm.org/fossil/artifact/ee53ffbf762?ln=161-232

Background: The sqlite3_set_authorizer() interface was first added for
CVSTrac (http://www.cvstrac.org).  The Fossil report logic was copied
from CVSTrac.

-- 
D. Richard Hipp
d...@sqlite.org
___
sqlite-users mailing list
sqlite-users@mailinglists.sqlite.org
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users


Re: [sqlite] Authorizer bypass "vulnerability"

2017-04-13 Thread Keith Medcalf

On Thursday, 13 April, 2017 06:14, Matthias-Christian Ott  
wrote:

> I'm unsure what the threat and security model of SQLite's authorizer
> callback is. I think it would only be an effective authorization
> mechanism if the attacker was able to only execute SQL statements on a
> database and the database was otherwise not accessible to the attacker.
> So I'm not sure whether the following behaviour should be seen as a
> vulnerability. Nonetheless, I wanted to point out SQLite's behaviour and
> document it.
 
> One of the parameters of the authorizer is the name of the database of
> the operation that is to be authorized. The documentation gives you the
> impression that "main" and "temp" are two reserved database names and
> cannot be changed. However, the name of the main database can be changed
> by sqlite3_db_config. So if the name of the main database is relevant to
> the authorizer, it must be impossible to change it through
> sqlite3_db_config (in the context of the application). The following
> code demonstrates the "problem":
 
> #include 
> #include 
> #include 
> #include 
> 
> int auth(void *p, int op, const char *name1, const char *name2,
>const char *dbname, const char *caller)
> {
> return dbname != NULL && strcmp(dbname, "main") == 0 ?
> SQLITE_DENY : SQLITE_OK;
> }

The implementation above is what is called "default permit".  This means that 
everything is permitted except that which has been defined by enumeration to be 
specifically denied.  This is the model used, for example, by most Antivirus 
programs.  It requires a complete enumeration of all possible badness in order 
to work and anything that is not specifically enumerated (such as a new malware 
variant) cannot be denied until it is added to the enumeration.

The proper model to use is "default deny", in which case everything is denied 
except for those things which are by enumeration permitted.  This is how most 
Discretionary Access Control Systems work (Login, Firewalls, etc).  That means 
that you cannot bypass the denial by becoming something unanticipated.  
Whitelisting software, for example, works this way too.

It is possible to use a "hybrid" model.  For example, you would check first to 
ensure that the database name is one of the ones that you are enumerating.  It 
not, then deny.  You can then, secure in the knowledge that the remainder of 
your authorization code is now limited only "enumerated" possibilities, so that 
if someone changes the database name to something unexpected the default is to 
deny.

However, in the case of SQLite (and many other authorization systems such as 
most DRM and copy protection), it is simply sufficient to use software that 
does not implement the authorizer in order to bypass it.  So in the case of 
SQLite just using the standard shell compiled without authorization hooks in 
place is sufficient to do what you will to the database (barring some other 
outer layer of protection limiting you to using only one specific set of code 
containing the authorizer functions to access the database file, such as 
application level encryption with the key being application specific).

The original Lotus 123 version 1a, for example, implemented a call to its 
authorizer (to make sure it was running from the original diskette) early in 
the startup code.  You simply replaced the machine code of the call with an XOR 
A INC A NOP NOP and the protection was bypassed entirely.





___
sqlite-users mailing list
sqlite-users@mailinglists.sqlite.org
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users


Re: [sqlite] Authorizer bypass "vulnerability"

2017-04-13 Thread Richard Hipp
On 4/13/17, Matthias-Christian Ott  wrote:
>
> It seems it is not possible to call sqlite3_db_config from SQL,

Exactly.  And since the programmers who implement the authorizer
callback know whether or not the database name has changed, they know
whether or not to check for "main" or some other name.  I do not
consider this to be a serious issue - certainly not worth adding a new
API or adding a new branch in a critical path that will slow down the
code in the common case.

-- 
D. Richard Hipp
d...@sqlite.org
___
sqlite-users mailing list
sqlite-users@mailinglists.sqlite.org
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users


[sqlite] Authorizer bypass "vulnerability"

2017-04-13 Thread Matthias-Christian Ott
I'm unsure what the threat and security model of SQLite's authorizer
callback is. I think it would only be an effective authorization
mechanism if the attacker was able to only execute SQL statements on a
database and the database was otherwise not accessible to the attacker.
So I'm not sure whether the following behaviour should be seen as a
vulnerability. Nonetheless, I wanted to point out SQLite's behaviour and
document it.

One of the parameters of the authorizer is the name of the database of
the operation that is to be authorized. The documentation gives you the
impression that "main" and "temp" are two reserved database names and
cannot be changed. However, the name of the main database can be changed
by sqlite3_db_config. So if the name of the main database is relevant to
the authorizer, it must be impossible to change it through
sqlite3_db_config (in the context of the application). The following
code demonstrates the "problem":

#include 
#include 
#include 
#include 

int auth(void *p, int op, const char *name1, const char *name2,
   const char *dbname, const char *caller)
{
return dbname != NULL && strcmp(dbname, "main") == 0 ?
SQLITE_DENY : SQLITE_OK;
}

int main()
{
int rc;
sqlite3 *db;

rc = sqlite3_open(":memory:", );
assert(rc == SQLITE_OK);
rc = sqlite3_exec(db, "CREATE TABLE t (i)", NULL, NULL, NULL);
assert(rc == SQLITE_OK);
rc = sqlite3_set_authorizer(db, , NULL);
assert(rc == SQLITE_OK);
rc = sqlite3_exec(db, "SELECT * FROM t", NULL, NULL, NULL);
assert(rc == SQLITE_AUTH);
rc = sqlite3_db_config(db, SQLITE_DBCONFIG_MAINDBNAME, "main2");
assert(rc == SQLITE_OK);
rc = sqlite3_exec(db, "SELECT * FROM t", NULL, NULL, NULL);
assert(rc == SQLITE_OK);
rc = sqlite3_close(db);
assert(rc == SQLITE_OK);

return 0;
}

It seems it is not possible to call sqlite3_db_config from SQL, so the
attacker would need to have access to the address space of the database
connection and the database file to bypass the authorizer.

Perhaps it makes sense to either always pass "main" as the database name
of the main database to the authorizer or to introduce an additional
function that allows to retrieve the main database name, for example
sqlite3_db_config_get.

- Matthias-Christian
___
sqlite-users mailing list
sqlite-users@mailinglists.sqlite.org
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users