SQLite3
SQLite3的架构分析可参考这里或官网
sqlite3_open() → rightarrow →openDatabase() → rightarrow →sqlite3_initialize()
功能包含Mutex初始化、Malloc初始化(某些全局变量、静态变量的初始化)、Page Cache(SQLite中处于B树和OS硬盘等操作接口之间,用于加速B树到文件介质之间的读写)初始化、Extra额外初始化……
sqlite3_exec()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
171.SQLITE_API int sqlite3_exec( 2. sqlite3 *db, /* The database on which the SQL executes */ 3. const char *zSql, /* The SQL to be executed */ 4. sqlite3_callback xCallback, /* Invoke this callback routine */ 5. void *pArg, /* First argument to xCallback() */ 6. char **pzErrMsg /* Write error messages here */ 7.){ 8. int rc = SQLITE_OK; /* Return code */ 9. const char *zLeftover; /* Tail of unprocessed SQL */ 10. sqlite3_stmt *pStmt = 0; /* The current SQL statement */ 11. char **azCols = 0; /* Names of result columns */ 12. int callbackIsInit; /* True if callback data is initialized */ 13. 14. if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; 15. ... 16.}
可以看到具体执行SQL语言之前会调用sqlite3SafetyCheckOk(),代码如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
321./* 2.** Check to make sure we have a valid db pointer. This test is not 3.** foolproof but it does provide some measure of protection against 4.** misuse of the interface such as passing in db pointers that are 5.** NULL or which have been previously closed. If this routine returns 6.** 1 it means that the db pointer is valid and 0 if it should not be 7.** dereferenced for any reason. The calling function should invoke 8.** SQLITE_MISUSE immediately. 9.** 10.** sqlite3SafetyCheckOk() requires that the db pointer be valid for 11.** use. sqlite3SafetyCheckSickOrOk() allows a db pointer that failed to 12.** open properly and is not fit for general use but which can be 13.** used as an argument to sqlite3_errmsg() or sqlite3_close(). 14.*/ 15.SQLITE_PRIVATE int sqlite3SafetyCheckOk(sqlite3 *db){ 16. u32 magic; 17. if( db==0 ){ 18. logBadConnection("NULL"); 19. return 0; 20. } 21. magic = db->magic; 22. if( magic!=SQLITE_MAGIC_OPEN ){ 23. if( sqlite3SafetyCheckSickOrOk(db) ){ 24. testcase( sqlite3GlobalConfig.xLog!=0 ); 25. logBadConnection("unopened"); 26. } 27. return 0; 28. }else{ 29. return 1; 30. } 31.}
从注释和代码可以看到,这个函数对db指针进行检查,会检测db指针是否为0或者通过Magic检测db指针是否曾被关掉。
也就是说db检查包括检查NULL、检查MAGIC是否OPEN。
sqlite3_close() → rightarrow →sqlite3Close()
再来看一下sqlite3Close的代码如下:
1
2
3
4
5
6
7
8
9
101.static int sqlite3Close(sqlite3 *db, int forceZombie){ 2. ... //一些清理工作 3. 4. /* Convert the connection into a zombie and then close it. 5. */ 6. db->magic = SQLITE_MAGIC_ZOMBIE; 7. sqlite3LeaveMutexAndCloseZombie(db); 8. return SQLITE_OK; 9.}
发现他会调用sqlite3LeaveMutexAndCloseZombie()来将对db的连接变成zombie,然后关掉,代码如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
201.SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){ 2. ... //数据结构的清理维护 3. 4. /* The temp-database schema is allocated differently from the other schema 5. ** objects (using sqliteMalloc() directly, instead of sqlite3BtreeSchema()). 6. ** So it needs to be freed here. Todo: Why not roll the temp schema into 7. ** the same sqliteMalloc() as the one that allocates the database 8. ** structure? 9. */ 10. sqlite3DbFree(db, db->aDb[1].pSchema); 11. sqlite3_mutex_leave(db->mutex); 12. db->magic = SQLITE_MAGIC_CLOSED; 13. sqlite3_mutex_free(db->mutex); 14. assert( db->lookaside.nOut==0 ); /* Fails on a lookaside memory leak */ 15. if( db->lookaside.bMalloced ){ 16. sqlite3_free(db->lookaside.pStart); 17. } 18. sqlite3_free(db); 19.}
发现代码最后有设置db->magic = SQLITE_MAGIC_CLOSED的操作,然后调用sqlite3_free()。
也就是说,MAGIC先设置为ZOMBIE,最后会设置为CLOSED,并且调用sqlite3_free()。
可能的UAF场景(硕士毕设开题前的杂记,可能有错)
我们已经可以发现db存在未被置NULL的问题,因此我们可以触发一些UAF问题,下面针对绕过MAGIC检查进行攻击。
Ring3的攻击
值得注意,db是处于Enclave内部的指针变量。
(1)Enclave线程A调用顺序乱序,但Enclave线程A、B不要求使用同一个db
Enclave线程A自己错误出现sql_close->sql_exec的调用场景,并且Enclave线程A、B不要求操控同一个db。
Enclave线程(也可以是进程,进程类似)A调用sql_close之后,magic设置为了MAGIC_CLOSED,但是db没有置成NULL。由于Enclave线程B的内存覆写(如对内存0x700地址(Enclave内)malloc并覆写,然后0x700刚好是MAGIC值)等问题导致db->magic虽然之前已经置成MAGIC_CLOSED,但是又被覆写置成了MAGIC_OPEN。导致线程A 执行sql_exec时,check里面的“db==0?”和“db->magic!=MAGIC_OPEN?”都被绕过。
(2)Enclave线程A调用顺序正确,但Enclave线程A、B使用同一个db
Enclave线程A调用sql_open然后正要sql_exec时,Enclave线程B对db进行了sql_close,并且还没来得及设置MAGIC值从MAGIC_OPEN变成MAGIC_ZOMBIE、MAGIC_CLOSED,此时部分的清理工作已经完成(虽然sqlite_free还没执行,sqlite_free晚于设置MAGIC_CLOSED,但是sql_close的很多清理工作已经做了),然后Enclave线程A里sql_exec的check就被绕过,然后往下执行,同时线程B继续完成db剩下的设置MAGIC_CLOSED和其他清理工作。
小结
上述两种本质都是magic状态被操纵导致绕过检查,第一种是通过间接的内存覆写(较难发生),第二种是对db、magic状态的直接改变。
Ring0的攻击
由于SGX的攻击者很可能是Ring0,这种条件下攻击者能力很强。
攻击者可以任意修改ECALL的调用顺序(通过修改不可信的EIP寄存器实现函数粒度)、任意暂停线程A的执行(AsyncShock的做法,清除Page PROT_READ、PROT_EXECUTE(mprotect)等构造异常使Enclave执行AEX从而被暂停,其实SGX-Step等利用异常或中断也提供了暂停原语),因此除了上述的Ring3攻击,Ring0攻击可以提供更多的UAF机会。
(修正:线程进入Enclave,会切换上下文寄存器,RIP寄存器也会切换,使用指定SSA里的RIP,因此无法通过修改不可信世界的RIP来进行代码粒度的控制流劫持,是否有方法篡改可信世界的SSA保存的RIP进行攻击尚不清楚。Mprotect和页表项Flag位和Execute Disable Bit关系猜想就后面)
(3)Enclave线程A、B不要求操控同一个db,攻击者可以恶意的通过不可信EIP篡改函数粒度控制流,攻击者不会任意暂停线程
攻击者让Enclave线程A执行sql_open->sql_close->sql_exec的过程(乱序)。在sql_close完成后,MAGIC变成MAGIC_CLOSED。但是由于Enclave线程B的malloc及内存覆写,将MAGIC_CLOSED变成了MAGIC_OPEN,使得Enclave线程A的sql_exec的check被绕过。
(4) Enclave线程A、B操控同一个db的场景下,攻击者不恶意通过不可信EIP篡改控制流,攻击者可以任意暂停线程
Enclave线程A执行sql_open、sql_exec,并且在线程A sql_exec的check之前暂停,然后启动线程B,使线程B sql_close完成部分清理工作时暂停线程B。此时MAGIC没法设置为MAGIC_CLOSED(虽然sql_free也还没执行,sql_free晚于MAGIC_CLOSED设置)。然后恢复线程A执行,这样就能绕过线程A 的sql_exec的check。然后再暂停线程A,恢复线程B完成MAGIC_CLOSED设置和sql_free工作。然后恢复线程A,就能出现问题。
小结
有了暂停功能可以让UAF的实现非常轻松。以上是以绕过check为目的UAF攻击,想要实现其他控制流劫持应该类似。
以上都是考虑受害者代码中没加设置db=NULL的过程。如果加上db=NULL,在Ring0攻击下,由于攻击者可以任意暂停线程,那么攻击者可以在线程B sql_free(sql_close的最后步骤)和db=NULL之间暂停线程B,然后让线程A sql_exec绕过db==NULL的检查(AsynShock做法,类似于前面讲的在sql_close完成前期的清理工作和MAGIC_CLOSED设置之间进行暂停)。因此,既然Ring0攻击可以任意暂停线程,那么加了db=NULL也不管用。
SGX_SQLite未对数据库文件密封(备忘)
数据库文件打开操作调用栈如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35ocall_open64(const char * filename, int flags, mode_t mode) (homeleone文档SGX_SQLiteAppocalls.c:42) Enclave_ocall_open64(void * pms) (homeleone文档SGX_SQLiteAppEnclave_u.c:248) libsgx_urts.so!do_ocall(const bridge_fn_t bridge, void * ms) (homeleone文档linux-sgxpswurtslinuxsig_handler.cpp:251) libsgx_urts.so!CEnclave::ocall(CEnclave * const this, const unsigned int proc, const sgx_ocall_table_t * ocall_table, void * ms) (homeleone文档linux-sgxpswurtsenclave.cpp:440) libsgx_urts.so!sgx_ocall(const unsigned int proc, const sgx_ocall_table_t * ocall_table, void * ms, CTrustThread * trust_thread) (homeleone文档linux-sgxpswurtsroutine.cpp:83) libsgx_urts.so!stack_sticker() (homeleone文档linux-sgxpswurtslinuxenter_enclave.S:244) __morestack() (homeleone文档linux-sgxsdktrtslinuxtrts_pic.S:435) __morestack() (homeleone文档linux-sgxsdktrtslinuxtrts_pic.S:435) sgx_ocall(const unsigned int index, void * ms) (homeleone文档linux-sgxsdktrtstrts_ocall.cpp:64) ocall_open64(int * retval, const char * filename, int flags, mode_t mode) (homeleone文档SGX_SQLiteEnclaveEnclave_t.c:909) open64(const char * filename, int flags) (homeleone文档SGX_SQLiteEnclaveocall_interface.c:36) posixOpen(const char * zFile, int flags, int mode) (homeleone文档SGX_SQLiteEnclavesqlite3.c:30223) robust_open(const char * z, int f, mode_t m) (homeleone文档SGX_SQLiteEnclavesqlite3.c:30522) unixOpen(sqlite3_vfs * pVfs, const char * zPath, sqlite3_file * pFile, int flags, int * pOutFlags) (homeleone文档SGX_SQLiteEnclavesqlite3.c:35686) sqlite3OsOpen(sqlite3_vfs * pVfs, const char * zPath, sqlite3_file * pFile, int flags, int * pFlagsOut) (homeleone文档SGX_SQLiteEnclavesqlite3.c:20291) sqlite3PagerOpen(sqlite3_vfs * pVfs, Pager ** ppPager, const char * zFilename, int nExtra, int flags, int vfsFlags, void (*)(DbPage *) xReinit) (homeleone文档SGX_SQLiteEnclavesqlite3.c:51710) sqlite3BtreeOpen(sqlite3_vfs * pVfs, const char * zFilename, sqlite3 * db, Btree ** ppBtree, int flags, int vfsFlags) (homeleone文档SGX_SQLiteEnclavesqlite3.c:61376) openDatabase(const char * zFilename, sqlite3 ** ppDb, unsigned int flags, const char * zVfs) (homeleone文档SGX_SQLiteEnclavesqlite3.c:143430) sqlite3_open(const char * zFilename, sqlite3 ** ppDb) (homeleone文档SGX_SQLiteEnclavesqlite3.c:143598) ecall_opendb(const char * dbname) (homeleone文档SGX_SQLiteEnclaveEnclave.cpp:21) sgx_ecall_opendb(void * pms) (homeleone文档SGX_SQLiteEnclaveEnclave_t.c:223) trts_ecall(uint32_t ordinal, void * ms) (homeleone文档linux-sgxsdktrtstrts_ecall.cpp:304) _random_stack_noinline_wrapper<_status_t, unsigned int, void*, int&, void*&>(_status_t (*)(unsigned int, void *) f) (homeleone文档linux-sgxcommonincsgx_random_buffers.h:83) random_stack_advance<2048u, _status_t, unsigned int, void*, int&, void*&>(_status_t (*)(unsigned int, void *) f) (homeleone文档linux-sgxcommonincsgx_random_buffers.h:102) do_ecall(int index, void * ms, void * tcs) (homeleone文档linux-sgxsdktrtstrts_ecall.cpp:438) enter_enclave(int index, void * ms, void * tcs, int cssa) (homeleone文档linux-sgxsdktrtstrts_nsp.cpp:96) enclave_entry() (homeleone文档linux-sgxsdktrtslinuxtrts_pic.S:181) libsgx_urts.so!__morestack() (homeleone文档linux-sgxpswurtslinuxenter_enclave.S:77) libsgx_urts.so!do_ecall(const int fn, const void * ocall_table, const void * ms, CTrustThread * trust_thread) (homeleone文档linux-sgxpswurtslinuxsig_handler.cpp:242) libsgx_urts.so!CEnclave::ecall(CEnclave * const this, const int proc, const void * ocall_table, void * ms, const bool is_switchless) (homeleone文档linux-sgxpswurtsenclave.cpp:387) libsgx_urts.so!_sgx_ecall(const sgx_enclave_id_t enclave_id, const int proc, const void * ocall_table, void * ms, const bool is_switchless) (homeleone文档linux-sgxpswurtsroutine.cpp:55) libsgx_urts.so!sgx_ecall(const sgx_enclave_id_t enclave_id, const int proc, const void * ocall_table, void * ms) (homeleone文档linux-sgxpswurtsroutine.cpp:68) ecall_opendb(sgx_enclave_id_t eid, const char * dbname) (homeleone文档SGX_SQLiteAppEnclave_u.c:387) main(int argc, char ** argv) (homeleone文档SGX_SQLiteAppApp.cpp:50)
数据库文件写
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41ocall_write(int fd, const void * buf, size_t count) (homeleone文档SGX_SQLiteAppocalls.c:56) Enclave_ocall_write(void * pms) (homeleone文档SGX_SQLiteAppEnclave_u.c:280) libsgx_urts.so!do_ocall(const bridge_fn_t bridge, void * ms) (homeleone文档linux-sgxpswurtslinuxsig_handler.cpp:251) libsgx_urts.so!CEnclave::ocall(CEnclave * const this, const unsigned int proc, const sgx_ocall_table_t * ocall_table, void * ms) (homeleone文档linux-sgxpswurtsenclave.cpp:440) libsgx_urts.so!sgx_ocall(const unsigned int proc, const sgx_ocall_table_t * ocall_table, void * ms, CTrustThread * trust_thread) (homeleone文档linux-sgxpswurtsroutine.cpp:83) libsgx_urts.so!stack_sticker() (homeleone文档linux-sgxpswurtslinuxenter_enclave.S:244) __morestack() (homeleone文档linux-sgxsdktrtslinuxtrts_pic.S:435) __morestack() (homeleone文档linux-sgxsdktrtslinuxtrts_pic.S:435) sgx_ocall(const unsigned int index, void * ms) (homeleone文档linux-sgxsdktrtstrts_ocall.cpp:64) ocall_write(int * retval, int fd, const void * buf, size_t count) (homeleone文档SGX_SQLiteEnclaveEnclave_t.c:1068) write(int fd, const void * buf, size_t count) (homeleone文档SGX_SQLiteEnclaveocall_interface.c:252) seekAndWriteFd(int fd, i64 iOff, const void * pBuf, int nBuf, int * piErrno) (homeleone文档SGX_SQLiteEnclavesqlite3.c:33147) seekAndWrite(unixFile * id, i64 offset, const void * pBuf, int cnt) (homeleone文档SGX_SQLiteEnclavesqlite3.c:33167) unixWrite(sqlite3_file * id, const void * pBuf, int amt, sqlite3_int64 offset) (homeleone文档SGX_SQLiteEnclavesqlite3.c:33234) sqlite3OsWrite(sqlite3_file * id, const void * pBuf, int amt, i64 offset) (homeleone文档SGX_SQLiteEnclavesqlite3.c:20172) writeJournalHdr(Pager * pPager) (homeleone文档SGX_SQLiteEnclavesqlite3.c:48434) pager_open_journal(Pager * pPager) (homeleone文档SGX_SQLiteEnclavesqlite3.c:52649) pager_write(PgHdr * pPg) (homeleone文档SGX_SQLiteEnclavesqlite3.c:52834) sqlite3PagerWrite(PgHdr * pPg) (homeleone文档SGX_SQLiteEnclavesqlite3.c:53007) newDatabase(BtShared * pBt) (homeleone文档SGX_SQLiteEnclavesqlite3.c:62172) sqlite3BtreeBeginTrans(Btree * p, int wrflag) (homeleone文档SGX_SQLiteEnclavesqlite3.c:62322) sqlite3VdbeExec(Vdbe * p) (homeleone文档SGX_SQLiteEnclavesqlite3.c:81529) sqlite3Step(Vdbe * p) (homeleone文档SGX_SQLiteEnclavesqlite3.c:76705) sqlite3_step(sqlite3_stmt * pStmt) (homeleone文档SGX_SQLiteEnclavesqlite3.c:76766) sqlite3_exec(sqlite3 * db, const char * zSql, sqlite3_callback xCallback, void * pArg, char ** pzErrMsg) (homeleone文档SGX_SQLiteEnclavesqlite3.c:111173) ecall_execute_sql(const char * sql) (homeleone文档SGX_SQLiteEnclaveEnclave.cpp:34) sgx_ecall_execute_sql(void * pms) (homeleone文档SGX_SQLiteEnclaveEnclave_t.c:270) trts_ecall(uint32_t ordinal, void * ms) (homeleone文档linux-sgxsdktrtstrts_ecall.cpp:304) _random_stack_noinline_wrapper<_status_t, unsigned int, void*, int&, void*&>(_status_t (*)(unsigned int, void *) f) (homeleone文档linux-sgxcommonincsgx_random_buffers.h:83) random_stack_advance<2048u, _status_t, unsigned int, void*, int&, void*&>(_status_t (*)(unsigned int, void *) f) (homeleone文档linux-sgxcommonincsgx_random_buffers.h:102) do_ecall(int index, void * ms, void * tcs) (homeleone文档linux-sgxsdktrtstrts_ecall.cpp:438) enter_enclave(int index, void * ms, void * tcs, int cssa) (homeleone文档linux-sgxsdktrtstrts_nsp.cpp:96) enclave_entry() (homeleone文档linux-sgxsdktrtslinuxtrts_pic.S:181) libsgx_urts.so!__morestack() (homeleone文档linux-sgxpswurtslinuxenter_enclave.S:77) libsgx_urts.so!do_ecall(const int fn, const void * ocall_table, const void * ms, CTrustThread * trust_thread) (homeleone文档linux-sgxpswurtslinuxsig_handler.cpp:242) libsgx_urts.so!CEnclave::ecall(CEnclave * const this, const int proc, const void * ocall_table, void * ms, const bool is_switchless) (homeleone文档linux-sgxpswurtsenclave.cpp:387) libsgx_urts.so!_sgx_ecall(const sgx_enclave_id_t enclave_id, const int proc, const void * ocall_table, void * ms, const bool is_switchless) (homeleone文档linux-sgxpswurtsroutine.cpp:55) libsgx_urts.so!sgx_ecall(const sgx_enclave_id_t enclave_id, const int proc, const void * ocall_table, void * ms) (homeleone文档linux-sgxpswurtsroutine.cpp:68) ecall_execute_sql(sgx_enclave_id_t eid, const char * sql) (homeleone文档SGX_SQLiteAppEnclave_u.c:397) main(int argc, char ** argv) (homeleone文档SGX_SQLiteAppApp.cpp:64)
最后
以上就是跳跃香氛最近收集整理的关于SGX_SQLite【源码分析】SQLite3sqlite3_open() → \rightarrow →openDatabase() → \rightarrow →sqlite3的全部内容,更多相关SGX_SQLite【源码分析】SQLite3sqlite3_open() 内容请搜索靠谱客的其他文章。
发表评论 取消回复