概述
SQLite3
SQLite3的架构分析可参考这里或官网
sqlite3_open() → rightarrow →openDatabase() → rightarrow →sqlite3_initialize()
功能包含Mutex初始化、Malloc初始化(某些全局变量、静态变量的初始化)、Page Cache(SQLite中处于B树和OS硬盘等操作接口之间,用于加速B树到文件介质之间的读写)初始化、Extra额外初始化……
sqlite3_exec()
1.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.** 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.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.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未对数据库文件密封(备忘)
数据库文件打开操作调用栈如下
ocall_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)
数据库文件写
ocall_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() → \rightarrow →openDatabase() → \rightarrow →sqlite3所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复