Re: [sqlite] Authorizer bypass "vulnerability"
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"
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"
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"
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:", &db); assert(rc == SQLITE_OK); rc = sqlite3_exec(db, "CREATE TABLE t (i)", NULL, NULL, NULL); assert(rc == SQLITE_OK); rc = sqlite3_set_authorizer(db, &auth, 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